C#の非同期処理まとめ
C#で非同期処理する方法がいろいろあって混乱したので、勉強してみました。
非同期処理について
こんなコードは不要
- Task.Run(), Task.Factory.StartNew(),Task.Start()
- Task.Wait(), Task.Result
- Threadクラスを直接使う
じゃあ、どうする?
実装編
- Asyncたちに対してawaitをつけることで、帰りを待つ
- Taskという戻り値では、中でAsyncを読んでいるため、帰らぬ前にアクセスしないように抑制できる。
- とりあえず"await"キーワードを利用したら明示的に関数名の頭に"async"をつける
- 非同期関数の戻り値をvoidとすることは滅多に無い。voidにすると呼び出し側では処理結果を感知しない。
- 注意:"await" はあくまで非同期的に待つ。従って、呼び出したスレッドはそのまま実行される。呼び出しスレッドにて実行終了を待つ場合は以下
public static void Main(string[] args) { // Step1: Task.Wait()を使わざるを得ない。 Task task = DownloadAsync(); task.Wait(); }
Task.Wait()を利用して、完了を待つ。ただしGUIアプリケーション(WPF/UWP/Xamarinなど)でTask.Wait()を呼び出すと、もれなくデッドロック のおまけがもらえる
非同期処理の勘所
- 呼び出し元が、呼び出し先の関数の結果に感知しない(興味が無い)場合は、非同期での実装を考える。
少し深い話
非同期処理について
- 非同期でawaitしてダウンロードなどを待つ場合、完了時の処理は呼び出したスレッドで実行される! 注意:iOSと異なる! メタい話:内部ではSynchronizationContextクラスを利用して呼び出し元に処理を投げてる
非同期対応ではない処理に対応する
- Task.Runを利用する。ワーカースレッドなるものに処理を投げつける。
- ワーカースレッドはDispatcherで同期する
- Task.Run はTaskを返すので、await可能
非同期処理とワーカースレッド
- どうやら違うらしい
- Task.Runはワーカースレッドを利用するため、CPUのコストが高い。
- 非同期処理はCPUのコストを可能な限り使わない。
- じゃあいつTask.Runするの?
- すっごい重い計算(仕方ない派)
- Async関数が無いレガシーなやつ
参考URL
大変わかりやすくて、勉強になりました。