なんとかするから、なんとかなる

エンジニア関係のことを書きます

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

大変わかりやすくて、勉強になりました。