イベントハンドラで同期・非同期処理をする実装パターン
イベント・イベントハンドラであっても、asyncメソッドの実装時と考え方は同じだが、イベントという皮を被ると少しわかりにくくなるのでまとめておく。
【Case 1】イベントソースは、イベントハンドラの完了を待機して抜けたい
# | awaitしたい? | イベントソース側 | イベントハンドラ側 |
---|---|---|---|
1-1 | - | イベントをInvoke | 同期処理する |
1-2 | 〇 | 非同期イベントをawait Invokeして完了待機 | async Taskメソッドにする |
1-2ではイベントハンドラが複数登録されていた場合、awaitのタイミングで後続のイベントハンドラが走り始めるので並列になる。工夫すれば逐次実行にもできる。実装例は以下を参照。
【Case 2】イベントソースは、イベントハンドラの処理が終わる前に抜けたい。イベントが連続的に発生する状況でイベントハンドラの処理順の保証は不要
# | awaitしたい? | イベントソース側 | イベントハンドラ側 |
---|---|---|---|
2-1 | - | イベントのInvokeをTask.Runでくるむ | 同期処理する |
2-2 | 〇 | イベントをInvoke | async voidメソッドにする |
2-1ではイベントハンドラの逐次呼び出しをTask.Runで包んでいるので、イベントハンドラの処理が並列にならないことに注意。
2-2ではイベントハンドラが複数登録されていた場合、awaitのタイミングで後続のイベントハンドラが走り始めるので並列になる。
【Case 3】イベントソースは、イベントハンドラの処理が終わる前に抜けたい。イベントが連続的に発生する状況でイベントハンドラの処理順を保証したい
# | awaitしたい? | イベントソース側 | イベントハンドラ側 |
---|---|---|---|
3 | -/〇 | イベントをInvoke | BlockingCollectionを使用したプロデューサーコンシューマーパターンで別スレッドへキューイングして処理するようにして、ハンドラ自体はすぐに抜ける |