Ожидаемая ссылка на пример кода
Примеры в этом справочнике демонстрируют Awaitable решения общих сценариев, встречающихся при написании асинхронного кода.
Асинхронные тесты
Unity Рамки тестирования не признает Awaitable в качестве действительного тестового типа возврата. Однако в следующем примере показано, как можно использовать Awaitable осуществление IEnumerator для написания асинхронных тестов:
[UnityTest]
public IEnumerator SomeAsyncTest(){
async Awaitable TestImplementation(){
// test something with async / await support here
};
return TestImplementation();
}
Фрейм-корутины
Вы можете использовать связанные с кадрами асинхронные методы в Awaitable класс, чтобы создавать асинхронные корутины 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, вы можете обернуть его в .NET Task. Это требует затрат на выделение, но дает вам доступ к таким методам, как WhenAll и WhenAny из Task API. Чтобы сделать это, вы можете написать свои собственные методы расширения 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;
}
Безопасная версия
Это один из сценариев, в котором вы можете обернуть Ожидаемое в Задачу за счёт распределения. 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;
}