异步方法 vs UniTask 返回

问题描述 投票:0回答:1

我正在尝试使用 UniTask 库来了解异步编程在 Unity 中的工作原理。

假设我们有这段代码:

private async UniTask LoadGameAsync()
{
    //this should be the right way to await the scene loading
    await LoadSceneAsync("Level_01");
    Debug.Log("Level 01 finished loading.");
    
    //does this work?
    //I'm uncertain if this is correct because I await a non async method. But then again it returns a task ... No compiler error.
    await LoadScene("Level_02");
    Debug.Log("Level 02 finished loading.");
    
    //why all this?
    //because I want to load multiple scenes simultaneously and only when all are finished loading, hide a loading screen.
    //Does this work the way I intend to or are there pitfalls to avoid? If so, what's the correct way of implementing something like this?
    UniTask level03Task = LoadScene("Level_03");
    UniTask level03UITask = LoadScene("Level_03_UI");
    await UniTask.WhenAll(level03Task, level03UITask);
    Debug.Log("Level 03 and its UI finished loading, hide loading screen now.");
}

private async UniTask LoadSceneAsync(string sceneName)
{
    await SceneManager.LoadSceneAsync(sceneName).ToUniTask();
}

private UniTask LoadScene(string sceneName)
{
    return SceneManager.LoadSceneAsync(sceneName).ToUniTask();
}

代码中的注释基本上概括了我的问题。是否可以从方法返回 UniTask 然后等待它?不知何故感觉不对,因为该方法基本上与异步方法相同,但......不是异步。

如果这不能按预期工作,实现我想象的正确方法是什么?

请注意,与 Task 相比,UniTask 是一个结构体,而不是一个类。不确定这在创建供以后使用的任务时是否会产生影响。

谢谢!

c# unity-game-engine asynchronous async-await
1个回答
0
投票

我不确定这是否正确,因为我等待非异步方法。但它再次返回一个任务...没有编译器错误。

您不等待任何方法,而是等待可等待的对象。到目前为止,您没有等待任何方法,而是等待它返回的对象。它可以是

Task
UniTask
或与
await
关键字兼容的任何其他对象。

在底层,

async/await
被重构为一个没有
async/await
关键字的状态机,但仅通过调用可等待对象的方法以及一些辅助对象来创建或执行其他操作。你可以尝试检查它,以及SharpLab中的其他语法糖。

   //why all this?
   //because I want to load multiple scenes simultaneously and only when all are finished loading, hide a loading screen.
   //Does this work the way I intend to or are there pitfalls to avoid? If so, what's the correct way of implementing something like this?
   UniTask level03Task = LoadScene("Level_03");
   UniTask level03UITask = LoadScene("Level_03_UI");
   await UniTask.WhenAll(level03Task, level03UITask);
   Debug.Log("Level 03 and its UI finished loading, hide loading screen now.");

让我们来处理这个问题。

    UniTask level03Task = LoadScene("Level_03");
    UniTask level03UITask = LoadScene("Level_03_UI");

这两行将立即执行。他们开始场景加载过程并创建一个句柄(

UniTask
s),可用于处理此过程。

    await UniTask.WhenAll(level03Task, level03UITask);

这一行使用两个任务来创建第三个任务,这将是它们完成的句柄。而且这个任务创建后,立刻就被

await
ed了。因此,只有等待的任务完成后,该方法才会继续执行。并在完成两个场景加载任务后完成。

到目前为止,如果你想显示任何加载UI,你必须在这一行之前显示它并在这一行之后隐藏。

请注意,与 Task 相比,UniTask 是一个结构体,而不是一个类。不确定这在创建供以后使用的任务时是否会产生影响。

总的来说,除了

UniTask
Task
类型之外,
struct
class
还有更深层次的差异。在大多数情况下,当您使用 Unity API 时,您不会注意到它们之间的任何差异。也许我可以提到的是,默认情况下,
UniTask
在 Unity 主循环内执行,而
Task
在单独的线程中执行
 by default
,这可能会导致访问某些 Unity API 时出现问题.

© www.soinside.com 2019 - 2024. All rights reserved.