Async/await
以下のC#メソッド(関数)は、指定されたURIからリソースをダウンロードし、そのリソースの長さを返す。
まず、asyncキーワードはC#コンパイラーに対してメソッドが非同期であることを示す。つまり、任意の数のawait式を使用でき、結果をpromiseにバインドする。
戻り値の型であるTask<T> は、C#におけるpromiseの類似形であり、ここではint型の結果値を持つことが示されている。
このメソッドが呼び出されたときに最初に実行される式は、new WebClient() である。DownloadDataTaskAsync(uri)は、Task<byte[]>を返す別の非同期メソッドである。このメソッドは非同期であるため、戻る前にデータのバッチ全体をダウンロードしない。代わりに、非ブロッキングメカニズム(ハードウェアによりオフロードされた実行コンテキストや、バックグラウンドスレッドなど)を使用してダウンロードプロセスを開始し、解決も拒否もされていないTask<byte[]>をこのメソッドに対して即座に返す。
Taskにアタッチされたawaitキーワードによって、このメソッドはすぐにTask<int>を呼び出し元に返し、呼び出し元は必要に応じて他の処理を続行できる。
DownloadDataTaskAsync()がダウンロードを完了すると、そのダウンロードしたデータによって、以前返却していたTaskを解決する。
C#の特定のケース、およびこの言語機能を備えた他の多くの言語では、async/awaitパターンは言語のランタイムのコアパーツではなく、コンパイル時にラムダまたは継続を使用して実装される。たとえば、C#コンパイラーは、上記のコードをIL バイトコード形式に変換する前に、次のようなコードに変換する可能性がある。
このため、インターフェイスメソッドがpromiseオブジェクトを返す必要があるが、それ自体が非同期タスクを待機するawaitに本文での待機を必要としない場合、async修飾子も必要なく、代わりにpromiseオブジェクトを直接返すことができる。たとえば、関数はいくつかの結果値(C#のTask.FromResult()など)にすぐに解決されるプロミスを提供できる場合があり、または単純に、必要な正確なプロミスである別のメソッドのプロミスを返す場合もある(オーバーロードによって遅延する場合など)。
しかし、この機能の一つの重要な注意点は、コードは従来のブロッキングコードに似ている一方で、コードが実際に非ブロックおよびマルチスレッドであることにより、awaitの付いた目標のプロミスが解決するのを待っている間に、多くの介在事象が発生する可能性があることを意味する。たとえば、次のコードは、awaitなしで常にブロッキングモデルで成功するが、await中にイベントが発生する可能性があるため、その下から共有状態が変更されていることがわかる。
2007年のF#リリースには、「非同期ワークフロー」が含まれている 。非同期ワークフローはCE(コンピュテーション式)として記述され、(C#のasyncのような)特別なコンテキストを指定することなく定義できる。非同期ワークフローを開始するには、キーワードに感嘆符(!)を付加する。
次の非同期関数では、非同期ワークフローを使用してURLで示すデータをダウンロードする。