包含此页的版本:
不含此页的版本:
本参考中的示例演示了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();
...
}
要解决Awaitable您可以将其包装在 .NET 中Task.这会产生分配成本,但允许您访问诸如WhenAll和WhenAny从Task应用程序接口。为此,您可以编写自己的自定义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;
}
}
之间的主要区别Awaitable和Task那是Awaitable对象被池化以减少分配。你不能安全地await一Awaitable-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;
}