Code

2015年9月12日土曜日

C# asyn と await の使い方

 先週、やっとアプリを App Store にサブミットしました。ついでに、バックエンドの Web Api も Refactoring して、もっと速くなりました。その改善の一つとしては、HttpClient を使って、他の Endpoint からデータを取得する処理を全て async にしました。たとえば、三つの Http Call をするところ、await Task.WhenAll(<TaskList>) を使って、Concurrency になりました。三つ Call を並べたら、500 ms * 3 の処理を、500ms ちょっとでできます。
 ただ、一つだけ、最初は Task.Run() を使って、そのタスクを await しようとのコードを発見しました。それは間違いです。なぜなら、Task.Run は Thread pool から一つのスレッドを申請して、そのタスクを実行しようとします。本来、現在のスレッドを await すると、もっと別のリクエスト処理できるのに、逆にもう一つのスレッドを使ったので、async の意味がなくなります。タスクを await すると、IO の処理は実行している間、CPU Heavey の処理が実行できますし、今のスレッドを一時的に手放して、他のリクエストも処理できます。遅い IO 処理が終わったら、また元の Call Context から処理を Resume して、本来のタスクを完成します。
 一つの Best Practice としては、async を使うと、Top-Down で全てを async にしたほうがいいです。そうしないと、デッドロックが発生するかもしれない。参考として下記のブログが詳しく説明されています。
 async を block しないで

 また、ASP.NET で await void を関数をできるだけ使わないでください。こちらは実際問題が起こされて、一つの AWS Box が応答しなくなりました。原因はまだ調査していますが、await void は結構危険です。
 それでは。