使用 Awaitable 进行异步编程的简介
Understand the key features of Unity's Awaitable and how it compares to both .NET Task and iterator-based coroutines.
阅读时间7 分钟最后更新于 1 个月前
- Unity 协程:、
NextFrameAsync、WaitForSecondsAsync、EndOfFrameAsyncFixedUpdateAsync - 切换到后台线程或主线程
- 继承自 的所有类型
AsyncOperation - Unity 事件
- 异步 GPU 回读
您可以在自己的代码中将 类与 运算符结合使用,并作为 返回类型使用,如下所示:
Awaitableawaitasyncasync Awaitable<List<Achievement>> GetAchievementsAsync(){ var apiResult = await SomeMethodReturningATask(); // or any await-compatible type List<Achievement> achievements = JsonConvert.DeserializeObject<List<Achievement>>(apiResult); return achievements;}async Awaitable ShowAchievementsView(){ ShowLoadingOverlay(); List<Achievement> achievements = await GetAchievementsAsync(); HideLoadingOverlay(); ShowAchivementsList(achievements);}
Awaitable 与 .NET Task 相比
最重要的限制是 实例会被池化以限制分配。请参考以下示例:
Awaitableclass SomeMonoBehaviorWithAwaitable : MonoBehavior{ public async void Start() { while(true) { // do some work on each frame await Awaitable.NextFrameAsync(); } }}
如果不池化,此示例中的每个 实例都会每帧分配一个 对象,从而增加垃圾回收器工作量并降低性能。为了缓解此问题,Unity 会在等待 对象后将其返回到内部 池。
MonoBehaviorAwaitableAwaitableAwaitable重要提示: 实例池意味着在一个 实例上多次 永远不会安全。这样做可能会导致未定义的行为,例如异常或死锁。
AwaitableAwaitableawaitAwaitable 与 .NET ValueTask 相比
.NET 具有与 相同的一些主要优点和限制。 的典型推荐用途是用于大多数时间预期同步完成的异步工作负载。有关更多信息,请参阅了解使用 ValueTask 的原因、方式和时间。
ValueTask<TResult>AwaitableValueTaskAwaitable、Task 和 ValueTask 汇总
下表总结了 Unity 的 类与 .NET 和 之间的功能比较:
AwaitableTaskValueTask功能 |
|
|
|
|---|---|---|---|
| 所需分配 | 多次。 在每次调用 | 根据需要。 可利用池化功能进行优化。 | 按需最低程度。 调用 |
| 可安全地等待多次 | 是。 | 否。 必须转换为具有 | 否。 必须转换为具有自定义 |
| 延续异步运行 | 是。 默认情况下使用同步上下文,否则使用 | 是。 针对等待的任务同步完成的情况进行了优化。如果是异步完成的,则继续行为等同于 | 否。 触发完成时,继续同步运行,这意味着代码会立即在触发完成的同一帧中恢复。请参阅“Awaitable 完成和延续”以了解更多信息。 |
| 可通过代码触发完成 | 是。 使用 | 不适用于典型的用例,这种情况下的任务大多同步完成。 | 是。 使用 |
| 可以返回值 | 是。 使用 | 是。 使用 | 是。 使用 |
内置对 | 是。 | 否。 必须转换为具有 | 否。 必须转换为具有自定义 |
| Unity 线程和更新循环感知执行调度 | 否。 | 否。 | 是。 您可以使用 |
何时使用 Awaitable 而非 Task 或 ValueTask
API 的选择取决于异步代码的性能配置文件,但一般情况下:
-
当您需要多次等待或同时等待多个消耗者时,是唯一的选择。
Task -
如果您的高吞吐量异步代码大多数时间都是同步完成的,是不错的选择。
ValueTask -
在以下情况下是不错的选择:
Awaitable- 您无需多次等待您的方法并期望基本上异步完成。
- 您希望异步任务具有对特定于 Unity 的概念(如主线程以及 Update 和 FixedUpdate 循环)的内置支持。
Awaitable 相比于基于迭代器的协程
AwaitableWaitForFixedUpdate但是,当同时运行许多 协程时,协程的性能优势会降低。例如,在 循环中等待 的 MonoBehaviour(如前一个代码示例所示)如果附加到大型项目中的每个游戏对象,可能会导致性能问题。
AwaitablewhileAwaitable.NextFrameAsync