async/awaitキーワードのつかいどころを調べてみた
使いまくってもハマるだけであまりいいことはないみたいなので、つかいどころだけ。
オーバーヘッドも馬鹿になりませんからね。
非同期処理はスレッドベースからタスクベースにしよう
そもそもの前提ですが、スレッドベースの非同期処理は今や非推奨らしいです。その証拠に、ストアアプリ版のAPIからはThreadクラスが削除されています。なぜかというと、スレッドを作ったり切り替えたりするコストが大きいからだそうです。スレッドの切り替え処理にも結構オーバーヘッドがかかりますし、だいだいひとつのスレッドを作るのにローカルスタックを1MB消費するとか。1000スレッドくらい作るとメモリを食べつくして飢え死にします。やってられませんね。
非同期処理をするときは、Threadクラスを直接使うのではなくTask、せめてThreadPoolやTimerを使うようにしましょう。こうすることで、既存のスレッドをなるべく使いまわすように裏でよきに計らってくれるので、作らられるスレッドを必要最小限に抑えることができます。ざっくりとした作戦はそれほど難しくなくて、降ってきたタスクをキューに入れて、空いているスレッドに実行させるという感じです。
外の世界とやり取りする処理は非同期にしよう
外の世界とのやり取りが絡む処理は非同期にしましょう。たとえばファイル入出力やデータの送信などです。ご存知の方も多いと思いますが、ストアアプリ向けに提供されているAPIは同期的に入出力するメソッドがことごとくなくなっています。こういうときのためのasync/awaitです。
50msec以上かかる(かもしれない)処理は非同期にしよう
処理時間がかかりすぎている目安として50msecというのが提示されています。これを超える(かもしれない)処理は非同期処理以外提供しないというのがいまどきの.NETにおける潮流らしいです。これまで紹介してきた削除されたAPIはこの考えに基づいているそうです。
awaitするかContinueWithするか
Taskクラス、またはTask
var read = await ReadAsync(); //ここでスレッドが呼び出し元に戻る var result = await Task.Run(() => HeavyTask(read)); //ContinueWithを使うと var result = await ReadAsync(). //ここでスレッドは呼び出し元に戻らない ContinueWith(r => HeavyTask(r));
まとめ
スレッドベースの非同期処理は書かない
入出力は非同期処理するように書く
時間がかかる処理は非同期処理するように書く
ContinueWithを使うところは使う