非同期タスク(Async/Await)は.Net 4.5でどのように機能しますか?
いくつかのサンプルコード:
private async Task<bool> TestFunction()
{
var x = await DoesSomethingExists();
var y = await DoesSomethingElseExists();
return y;
}
2番目のawait
ステートメントはすぐに実行されますか、または最初のawait
が戻った後に実行されますか?
await
は、操作が完了するまでメソッドを一時停止します。したがって、2番目のawait
は、最初のawait
が戻った後に実行されます。
詳細については、my async
/await
intro または 公式FAQ を参照してください。
最初の待機が戻った後に実行されます。このことで混乱する場合は、ブレークポイントで遊んでみてください-新しい非同期パターンで完全にサポートされています。
次のようになると想像してください。
var x = await GetSomeObjectInstance();
var y = await GetSomeObjectInstance2(x);
おそらくどこかでNullReferenceExceptionが発生するため、最初の待機has toが最初に戻ります。それ以外の場合、x
はnull /未定義などになります。
メソッド呼び出しは、「通常の」待機されていないメソッド呼び出しと同様に、引き続き連続して発生します。 awaitの目的は、待機中の操作が実行されて何でもする間、現在のスレッドをスレッドプールに返すことです。
これは、特定のリクエストがスレッドプール全体の特定のスレッドで処理される、Webサーバーなどの高性能環境で特に役立ちます。待機しない場合、db /サービス呼び出しが完了するまで、要求(およびそのすべてのリソース)を処理する特定のスレッドは「使用中」のままです。これは、特に外部サービス呼び出しの場合、数秒以上かかる場合があります。
現在、トラフィックの少ないWebサイトではこれはそれほど問題ではありませんが、トラフィックの多いサイトでは、これらのすべてのリクエストスレッドのコストは、「使用中」状態で何もせずにdb/service呼び出しなどの他のプロセスを待つだけです戻ることはリソースの負担になる可能性があります。
スレッドを解放してワーカープールに戻し、他の要求に対して他の有用な作業を行えるようにする方がよいでしょう。
Db/service呼び出しが完了すると、スレッドプールに割り込み、中断したところからその要求の処理を続行するスレッドを要求できます。その時点で、リクエストの状態がリロードされ、メソッド呼び出しが続行されます。
したがって、awaitを使用する場合、リクエストごとに、リクエストはユーザーの観点からは同じ時間かかります ...に加えて、スイッチングオーバーヘッドのわずかな増加があります。
しかし、集計では、すべてのユーザーに対するすべてのリクエストにわたって、Webサーバー(この場合)がより効率的に実行され、リソース使用率が向上するため、すべてのユーザーにとってパフォーマンスが向上しているように見えます。すなわち、awaitが要求を返すため、要求を処理するために空きスレッドを待機している要求をキューに入れる必要がありません。あるいは、同じ量のハードウェアをより効率的に使用しているため、より多くのハードウェアを購入する必要がありませんスループット。
ただし、これには切り替えコストがかかるため、デフォルトのテンプレートや多くのドキュメントに見られるものにもかかわらず、すべてのコールに対して盲目的にawaitを使用するべきではありません。それは単なるツールであり、他のすべてのツールと同様にその場所を持っています。スイッチングのコストが、呼び出しを同期的に完了するだけのコスト以上である場合、awaitを使用しないでください。