Version: 6000.3
语言: 中文
等待的完成和延续
使用作业系统编写多线程代码

可等待的代码示例参考

本参考中的示例演示了Awaitable编写异步代码时遇到的常见场景的解决方案。

异步测试

Unity 的测试框架测试框架包(以前称为测试运行程序)是一种 Unity 工具,可在编辑模式和播放模式下测试代码,也可以在目标平台(如独立、Android 或 iOS)上测试代码。更多信息
请参阅术语表
不认识Awaitable作为有效的测试返回类型。但是,以下示例显示了如何使用Awaitable实现IEnumerator要编写异步测试:

[UnityTest]
public IEnumerator SomeAsyncTest(){
    async Awaitable TestImplementation(){
        // test something with async / await support here
    };
    return TestImplementation();
}

框架协程

你可以在Awaitableclass 创建异步 Unity 协程,作为基于迭代器的协程的替代方案:

async Awaitable SampleSchedulingJobsForNextFrame()
{
    // Wait until end of frame to avoid competing over resources with other Unity subsystems
    await Awaitable.EndOfFrameAsync(); 
    var jobHandle = ScheduleSomethingWithJobSystem();
    // Let the job execute while the next frame starts
    await Awaitable.NextFrameAsync();
    jobHandle.Complete();
    // Use results of computation
}

JobHandle ScheduleSomethingWithJobSystem()
{
    ...
}

有条件等待

在基于迭代器的协程中,WaitUntil 会暂停协程执行,直到委托计算true.您可以为Awaitable-returning 异步方法,方法是使用取消令牌让它等待条件更改:

public static async Awaitable AwaitableUntil(Func<bool> condition, CancellationToken cancellationToken)
{
   while(!condition()){
     cancellationToken.ThrowIfCancellationRequested();
     await Awaitable.NextFrameAsync();
  }
}

然后,您可以按如下方式传入取消令牌:

cancellationTokenSource = new CancellationTokenSource();
currentTask = AwaitableUntil(myCondition, cancellationTokenSource.Token);

异步加载资源

您可以await异步资源加载作,使其不会阻塞主线程:

public async Awaitable LoadResourcesAsync()
{
    // Load texture resource asynchronously
    var operation = Resources.LoadAsync("my-texture");
    // Return control to the main thread while the resource loads
    await operation;
    var texture = operation.asset as Texture2D;
}

组成

您可以await多种不同的await-compatible 类型:

public async Awaitable Bar()
{
    await CallSomeThirdPartyAPIReturningDotnetTask();
    await Awaitable.NextFrameAsync();
    await SceneManager.LoadSceneAsync("my-scene");
    await SomeUserCodeReturningAwaitable();
    ...
}

在 .NET 任务中包装 Awaitable

要解决Awaitable您可以将其包装在 .NET 中Task.这会产生分配成本,但允许您访问诸如WhenAllWhenAnyTask应用程序接口。为此,您可以编写自己的自定义AsTask扩展方法如下:

// Implement custom AsTask extension methods to wrap Awaitable in Task
public static class AwaitableExtensions
    {
        public static async Task AsTask(this Awaitable a)
        {
            await a;
        }

        public static async Task<T> AsTask<T>(this Awaitable<T> a)
        {
            return await a;
        }
    }

多次等待结果

之间的主要区别AwaitableTask那是Awaitable对象被池化以减少分配。你不能安全地awaitAwaitable-returning 方法多次完成结果,因为一旦返回原始Awaitable对象返回到池中。

不安全版本

以下代码不安全,会导致异常和死锁:

async Awaitable Bar(){
  var taskWithResult = SomeAwaitableReturningFunction();
  var awaitOnce = await taskWithResult;
  // Do something
  // The following will cause errors because at this point taskWithResult has already been pooled back
  var awaitTwice = await taskWithResult;
 }

安全版

这是可以以分配为代价将 Awaitable 包装在 Task 中的场景之一。这Task然后可以安全地等待多次:

// Implement custom AsTask extension methods to wrap Awaitable in Task
public static class AwaitableExtensions
    {
        public static async Task AsTask(this Awaitable a)
        {
            await a;
        }

        public static async Task<T> AsTask<T>(this Awaitable<T> a)
        {
            return await a;
        }
    }

async Awaitable Bar(){
  var taskWithResult = SomeAwaitableReturningFunction();
  // Wrap the returned Awaitable in a Task
  var taskWithResultAsTask = taskWithResult.AsTask();
  // The task can now be safely awaited multiple times, at the cost of allocating
  var awaitOnce = await taskWithResultAsTask;
  // Do something
  var awaitTwice = await taskWithResultAsTask;
 }

其他资源

等待的完成和延续
使用作业系统编写多线程代码