Unity 6.3
0 онлайн 95 гостей 3 в системе
Вход
Программирование в Unity Шаг 126 из 210

Ожидаемая ссылка на пример кода

Примеры в этом справочнике демонстрируют 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;
 }

Дополнительные ресурсы