ドキュメント

Unity Engine

Unity Engine

Awaitable のコード例リファレンス

Solve common asynchronous programming problems with a reference of Awaitable code examples.
読み終わるまでの所要時間 6 分最終更新 1ヶ月前

このリファレンスの例は、非同期コードの記述時に経験する一般的なシナリオに対する、
Awaitable
での解決策を示しています。

非同期テスト

Unity の Test Framework は、
Awaitable
を有効なテストの戻り値の型として認識しません。しかし、以下の例は、
IEnumerator
の
Awaitable
実装を使用して非同期テストを記述する方法を示しています。
[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(){ ...}

条件付き待機

イテレーターベースのコルーチンでは、デリゲートが
true
を評価するまで、WaitUntil はコルーチンの実行をサスペンドします。キャンセルトークンを使用して条件が変更されるまでメソッドを待機させることで、
Awaitable
を返す非同期メソッドと同等の動作を作成できます。
public static async AwaitableUntil(Func<bool> condition, CancellationTokenSource cancellationToken){ while(!condition()){ cancellationToken.ThrowIfCancellationRequested(); await Awaitable.NextFrameAsync(); }}
その後、以下のようにキャンセルトークンを渡すことができます。
cancellationTokenSource = new CancellationTokenSource();currentTask = AwaitableUntil(myCondition, cancellationTokenSource.Token);

リソースの非同期ロード

非同期のリソースロード操作を
await
して、メインスレッドをブロックしないようにすることができます。
public async Awaitable Start(){ // 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
できます。
public async Awaitable Start(){ await CallSomeThirdPartyAPIReturningDotnetTask(); await Awaitable.NextFrameAsync(); await SceneManager.LoadSceneAsync("my-scene"); await SomeUserCodeReturningAwaitable(); ...}

.NET タスクでの Awaitable のラッピング

Awaitable
の制限のいくつかを回避するために、.NET
Task
でラップします。これには割り当ての手間がかかりますが、
Task
API から
WhenAll
や
WhenAny
などのメソッドにアクセスできます。これを行うには、独自のカスタム
AsTask
拡張メソッドを次のように記述します。
// Implement custom AsTask extension methods to wrap Awaitable in Taskpublic 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; } }

結果を複数回 Await する

Awaitable
と
Task
の主な違いは、
Awaitable
オブジェクトは割り当てを減らすためにプールされることです。
Awaitable
を返すメソッド (1 つの結果を複数回返すことで完了する) を、安全に
await
することはできません。いったん返されると、元の
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 をラップ できるシナリオの 1 つです。こうすると、
Task
は複数回安全に await できます。
// Implement custom AsTask extension methods to wrap Awaitable in Taskpublic 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; }

追加リソース