Open棟梁Project - マイクロソフト系技術情報 Wiki
目次 †
概要 †
- async/awaitの登場で、マルチスレッド処理として実装しなくても、
非同期処理を同期型処理と、ほぼ変わらない記述で実装可能になった。
スレッド †
- スレッドの並列実行はOSが裏で無意識にしてくれていた。
- タイムスライスで細切れ/ラウンドロビンで論理的に並列実行。
- CPUのコア数に応じて、物理的に並列実行。
- しかし、以下の処理は意識的に実装する必要があった。
- 非同期処理をスレッド関数として分離して実装する。
- スレッド関数を作成したワーカースレッドに渡す。
- スレッド関数の結果をメインスレッドで待ち合わせる。
タスク †
- Taskを返す非同期メソッドを、
- asyncで修飾したメソッドから、awaitステートメントを付与して呼び出す。
- 若しくは、Task.Run()で実行して、Task.Wait()で待ち合わせる。
用途 †
- 主に、UIスレッドのハングアップを防止するために使用される。
- UIスレッドから、時間のかかるバックグラウンド処理
(ネットワーク バインドまたは I/O バインドの処理)を分離する。
- この仕組みは、Webサーバのスレッド枯渇を防ぐ非同期コントローラなどにも応用されている。
タスクの分割 †
awaitを切れ目として、プログラマが意識して時間のかかる
バックグラウンド処理(ネットワーク バインドまたは I/O バインドの処理)を分割する。
- await前の処理はフォアグラウンドで実行される。
- awaitで呼び出す非同期メソッドはバックグラウンドで実行される。
- await後の処理は、コールバックとして実装せずにフォアグラウンドに復帰する。
詳細 †
- 非同期化は、スレッドやWindowsメッセージングキューなどを使用して行われる。
- await、Task.Wait()の待ち合わせまでがセットになっている仕組みなので、
並列実行処理を実装するための基盤ではないことに注意。
使い方 †
- async/awaitの登場で、同期型処理と、ほぼ変わらない記述で実装可能になった。
- しかし、デバッグの時は非同期で実行されていることを意識する必要がある。
非同期メソッドの戻り値 †
void型 †
- 戻り値としてreturn文を書かない場合
- 「イベント・ハンドラかどうか」→ void型
Task型 †
- 戻り値としてreturn文を書かない場合
- 「待機したいかどうか」→ Task型
Task<T>型 †
- 非同期処理の結果を受け取りたい場合
- 戻り値はTask<T>型だが、returnするのはT型の値
非同期メソッドの呼び出し †
Task.Run()、Task.Wait()メソッド †
- Task.Run()
- 非同期メソッドを実行してTask、Task<TResult>を返す。
- Task.Wait()
- Task、Task<TResult>の実行が完了するまで待機する。
await演算子 †
- Task の実行が完了するまで待機する。
- await 非同期メソッド()
- await Task.Run()
- await演算子の使い方
- 非同期メソッドを呼び出すときに、await演算子(後述)を利用する。
- メソッド内でawait演算子(後述)を利用する場合、async修飾子でメソッドを修飾する。
- await演算子は、async修飾子の付くメソッドの中で1つ以上記述できる。
その他 †
Task.WhenAll?() †
- Task.WhenAll?()メソッドで複数のタスクを待機するタスクを取得する。
- このTaskをTask.Wait()するとTask毎の例外をAggregateException?型として取得可能。
スレッド同期 †
仕組みから †
スレッドを使用した処理を記述しないが、分割されたタスクは、
- 同一スレッドで動作することも
- 別スレッドで動作することもある。
このため、一連の処理が(分割されたタスクが)、
- 異なるスレッドで実装される保証は無い。
- 同じスレッドで実行される保証も無い。
スレッド同期ツールキットは使用不可 †
従って、スレッド同期のlock等は無意味。
従来のスレッド同期ツールキットは使用不可。
lock/mutex/semaphoreはtaskで全て使用禁止 †
WaitFor?[Single|Multi]Objectは例外的に使用可 †
これは、Win32の待機関数のWaitFor?[Single|Multi]Objectは、
スレッドに限らず様々な「オブジェクト」の状態が変化する(シグナル状態になる)のを待つ関数であるためと考える。
参考 †