# Awaitable を使用した非同期プログラミングの概要

> Understand the key features of Unity's Awaitable and how it compares to both .NET Task and iterator-based coroutines.

[`Awaitable`](/engine/6000.0/script-reference/unity-engine/awaitable.md) クラスは待機可能なカスタムの Unity 型で、C# 非同期プログラミングモデルで async の戻り値の型として使用できます。以下を含む Unity の非同期 API のほとんどは、`async` と `await` のパターンをサポートします。

* Unity コルーチン: [`NextFrameAsync`](/engine/6000.0/script-reference/unity-engine/awaitable/next-frame-async.md)、[`WaitForSecondsAsync`](/engine/6000.0/script-reference/unity-engine/awaitable/wait-for-seconds-async.md)、[`EndOfFrameAsync`](/engine/6000.0/script-reference/unity-engine/awaitable/end-of-frame-async.md)、[`FixedUpdateAsync`](/engine/6000.0/script-reference/unity-engine/awaitable/fixed-update-async.md)
* [バックグラウンドスレッド](/engine/6000.0/script-reference/unity-engine/awaitable/background-thread-async.md) または [メインスレッド](/engine/6000.0/script-reference/unity-engine/awaitable/main-thread-async.md) への切り替え
* [`AsyncOperation`](/engine/6000.0/script-reference/unity-engine/async-operation.md) を継承するすべての型
* [Unity Learn：イベント](/engine/6000.0/manual/scripting/object-oriented-development/event-handling/unity-events.md)
* [非同期 GPU リードバック](/engine/6000.0/script-reference/unity-engine-rendering/async-gpu-readback.md)

以下のように、`Awaitable` クラスを `await` 演算子と `async` の戻り値の型の両方とともに独自のコードで使用できます。

```lang-csharp
async Awaitable<List<Achievement>> GetAchievementsAsync()
{
    var apiResult = await SomeMethodReturningATask(); // or any await-compatible type
    List<Achievement> achievements = JsonConvert.DeserializeObject<List<Achievement>>(apiResult);
    return achievements;
}

async Awaitable ShowAchievementsView()
{
    ShowLoadingOverlay();
    List<Achievement> achievements = await GetAchievementsAsync();
    HideLoadingOverlay();
    ShowAchivementsList(achievements);
}
```

## Awaitable と .NET Task の比較##awaitable-compared-to-.net-task

`Awaitable` は、Unity プロジェクトの非同期コードに、.NET [`Task`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task?view=net-8.0) に代わるより効率的な方法を提供するように設計されています。`Awaitable` は効率的ですが、`Task` と比較して重要な制限があります。

最も重要な制限は、`Awaitable` インスタンスが割り当てを制限するためにプールされることです。以下の例を考えてみてください。

```lang-csharp
class SomeMonoBehaviorWithAwaitable : MonoBehavior
{
    public async void Start()
    {
        while(true)
        {
            // do some work on each frame
            await Awaitable.NextFrameAsync();
        }
    }
}
```

この例の [`MonoBehavior`](/engine/6000.0/manual/scripting/get-started/fundamental-unity-types/class-mono-behaviour.md) の各インスタンスは、プーリングを行わないと、フレームごとに `Awaitable` オブジェクトを割り当て、[ガベージコレクターのワークロード](/engine/6000.0/manual/analysis/performance-memory-overview/managed-memory/garbage-collector.md) を増加させ、パフォーマンスを低下させます。これを軽減するために、Unity は待機後に `Awaitable` オブジェクトを内部 `Awaitable` プールに返します。

**重要：**`Awaitable` インスタンスのプーリングは、1 つの `Awaitable` インスタンスを複数回 `await` することは決して安全ではないことを意味します。これを行うと、例外やデッドロックなどの未定義の動作につながる可能性があります。

## Awaitable と .NET ValueTask の比較##awaitable-compared-to-.net-valuetask

.NET [`ValueTask<TResult>`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask-1?view=net-8.0) は、`Awaitable` と同じ主なメリットと制限をいくつか提供します。`ValueTask` の推奨される一般的な使用法は、ほとんどの場合に同期的に完了すると予想される非同期ワークロードです。詳細については、[Understanding the Whys, Whats, and Whens of ValueTask](https://devblogs.microsoft.com/dotnet/understanding-the-whys-whats-and-whens-of-valuetask/) を参照してください。

## Awaitable、Task、ValueTask の要約##awaitable-task-and-valuetask-summary

以下の表は、Unity の `Awaitable` クラスと .NET `Task` および `ValueTask` の機能比較をまとめたものです。

| **機能**                                 | `Task`                                                                                                                                        | `ValueTask`                                                                                                                        | `UnityEngine.Awaitable`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **必要な割り当て**                            | **多い**。`Task` を返すメソッドの呼び出しごとに割り当てられ、メモリ使用量とガベージコレクターのワークロードが増加します。                                                                            | **必要に応じて**。プーリングを使用して最適化できます。                                                                                                      | **必要最小限**。`Awaitable` を返すメソッドを呼び出しても、通常はメモリは割り当てられません。`Awaitable` インスタンスはデフォルトでプールされるためです。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| **安全に複数回待機可能**                         | **可**。                                                                                                                                        | **不可**。`ValueTask.AsTask` で `Task` に変換する必要があります。                                                                                   | **不可**。カスタムの `AsTask` 拡張メソッドで `Task` に変換する必要があります。コード例リファレンスの [同じメソッド内での複数回の await](/engine/6000.0/manual/scripting/optimization/async-await-support/async-awaitable-examples.md#await-multiple-times) を参照してください。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| **継続の非同期実行**                           | **可**。同期コンテキストをデフォルトで使用します。それ以外の場合は `ThreadPool` を使用します。Unity のメインスレッドで完了するときに待ち時間が長くなります。これは、コードが再開されるために次のフレームの `Update` を待機する必要があるためです。    | **可**。待機中のタスクが同期的に完了するケースに最適化されています。非同期的に完了する場合、継続動作は `Task` と同じです。                                                                | **不可**。継続は、完了がトリガーされると同期的に実行されます。つまり、コードは、完了がトリガーされたのと同じフレーム内ですぐに再開されます。詳細については、[Awaitable の完了と継続](/engine/6000.0/manual/scripting/optimization/async-await-support/async-awaitable-continuations.md) を参照してください。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| **コードによって完了をトリガー可能**                   | **可**。[`TaskCompletionSource`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcompletionsource?view=net-8.0) を使用します。 | 一般的なユースケース (ほとんどの場合に同期的に完了するタスク) には適用されません。                                                                                        | **可**。[`AwaitableCompletionSource`](/engine/6000.0/script-reference/unity-engine/awaitable-completion-source.md) を使用します。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| **値を返すことが可能**                          | **可**。[`Task<TResult>`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1?view=net-8.0) を使用します。                      | **可**。[`ValueTask<TResult>`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask-1?view=net-8.0) を使用します。 | **可**。[`UnityEngine.Awaitable<T>`](/engine/6000.0/script-reference/unity-engine/awaitable-1.md) を使用します。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| **`WaitAll` および `WaitAny` のビルトインサポート** | **可**。                                                                                                                                        | **不可**。`ValueTask.AsTask` で `Task` に変換する必要があります。                                                                                   | **不可**。カスタムの `AsTask` 拡張メソッドで `Task` に変換する必要があります。コード例リファレンスの [.NET タスクでの Awaitable のラッピング](/engine/6000.0/manual/scripting/optimization/async-await-support/async-awaitable-examples.md#awaitable-as-task) を参照してください。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| **Unity スレッドと更新ループに対応した実行スケジュール**      | **不可**。                                                                                                                                       | **不可**。                                                                                                                            | **可**。[`Awaitable.BackgroundThreadAsync`](/engine/6000.0/script-reference/unity-engine/awaitable/background-thread-async.md) と [`Awaitable.MainThreadAsync`](/engine/6000.0/script-reference/unity-engine/awaitable/main-thread-async.md) を使用して、`Awaitable` を再開するスレッドを指定できます。また、[`Awaitable.NextFrameAsync`](/engine/6000.0/script-reference/unity-engine/awaitable/next-frame-async.md) と [`Awaitable.FixedUpdateAsync`](/engine/6000.0/script-reference/unity-engine/awaitable/fixed-update-async.md) を使用して、`Update` または `FixedUpdate` ループに関連して処理をスケジュールすることもできます。詳細については、[Awaitable の完了と継続](/engine/6000.0/manual/scripting/optimization/async-await-support/async-awaitable-continuations.md) を参照してください。 |

## Task または ValueTask よりも Awaitable を使用する場合##when-to-use-awaitable-over-task-or-valuetask

API の選択は非同期コードのパフォーマンスプロファイルによって異なりますが、一般的には以下のように選択します。

* `Task` は、複数回待機する必要がある場合や、複数のコンシューマーから同時に待機する必要がある場合の唯一の選択肢です。

* `ValueTask` は、ほとんどの場合に同期的に完了する高スループットの非同期コードがある場合に適しています。

* `Awaitable` は、以下のような場合に適しています。

  * メソッドを複数回待機する必要がなく、ほとんどが非同期的に完了する場合。
  * 非同期タスクに、メインスレッド、[Update](/engine/6000.0/manual/scripting/object-oriented-development/managing-time-and-frame-rate/time-per-frame-updates.md) ループ、[FixedUpdate](/engine/6000.0/manual/scripting/object-oriented-development/managing-time-and-frame-rate/fixed-updates.md) ループといった Unity 固有の概念のビルトインサポートが必要な場合。

## Awaitable とイテレーターベースのコルーチンの比較##awaitable-compared-to-iterator-based-coroutines

`Awaitable` コルーチンは、通常、イテレーターベースのコルーチンよりも効率的です。特に、イテレーターが [`WaitForFixedUpdate`](/engine/6000.0/script-reference/unity-engine/wait-for-fixed-update.md) などの null 以外の値を返す場合に適しています。

ただし、多くの `Awaitable` コルーチンを同時に実行すると、パフォーマンス上のメリットが低下します。例えば、前述のコード例のような MonoBehaviour は、`while` ループで [`Awaitable.NextFrameAsync`](/engine/6000.0/script-reference/unity-engine/awaitable/next-frame-async.md) を待機しますが、大規模なプロジェクト内のすべてのゲームオブジェクトにアタッチされると、パフォーマンスの問題が発生する可能性があります。

## 追加リソース##additional-resources

* [Awaitable の完了と継続](/engine/6000.0/manual/scripting/optimization/async-await-support/async-awaitable-continuations.md)
* [Awaitable のコード例リファレンス](/engine/6000.0/manual/scripting/optimization/async-await-support/async-awaitable-examples.md)
