Upgrade to Pro — share decks privately, control downloads, hide ads and more …

パターンでわかる!​ ​ .NET Coreの​ 非同期処理

パターンでわかる!​ ​ .NET Coreの​ 非同期処理

.NET Core 3.0時点での、非同期処理にまつわる全てのキーポイントを解説しました。

発表動画もYouTubeで公開しているので、合わせて参照してください:
https://www.youtube.com/watch?v=YF7n8YqEfCg

.NET非同期処理のおさらい​
* 概要と基本的な書き方​
* コンソールアプリケーションとGUIアプリケーションとの違い​
* お勧めしたいプラクティスとアンチパターン​

.NET非同期処理の現実と設計​
* 現実的なアプリケーションへの適用と課題​
* 追加された非同期処理の要素​
* 足りなかったもの・足りていると勘違いされていたもの​

------

.NET Conf 2019 meetup in AICHI
https://centerclr.connpass.com/event/143949/

Kouji Matsui

October 05, 2019
Tweet

More Decks by Kouji Matsui

Other Decks in Programming

Transcript

  1. Kouji Matsui – kozy, kekyo • NAGOYA city, AICHI pref.,

    JP • Twitter – @kozy_kekyo, @kekyo2 / Facebook • Self employed (I’m looking for a job) • Microsoft Most Valuable Professional VS and DevTech 2015- • Certified Scrum master / Scrum product owner • Center CLR organizer. • .NET/C#/F#/IL/metaprogramming or like… • Bike rider
  2. What’s new features 本日は、以下のことをお話します: .NET非同期処理のおさらい ◦ 概要と基本的な書き方 ◦ コンソールアプリケーションとGUIアプリケーションとの違い ◦

    お勧めしたいプラクティスとアンチパターン .NET非同期処理の現実と設計 ◦ 現実的なアプリケーションへの適用と課題 追加された非同期処理の要素 ◦ 足りなかったもの・足りていると勘違いされていたもの
  3. What’s new features .NET Core 3とC# 8.0で、.NETの非同期処理はついに完成 Task async-await ValueTask

    IAsyncEnumerable Awaitable foreach 非同期処理記述の 容易さの壁 (1) 非同期処理記述の 容易さの壁 (2) 世 代 今日は、壁より前の話や内部の話はしません。 なぜ非同期で処理を行う必要があるのかについては、 「Async訪ねて3000里」を参照
  4. 基本的な操作 Appendix 戻り値の型 直接的な意味 処理の詳細 Task<T> 非同期処理を行いT型の結果 を返す 非同期処理を行い、処理完了後に 結果を値として返す

    Task 非同期処理を行い結果を返さ ない 非同期処理を行い、処理完了後に 完了したことだけが通知される T 同期処理でT型の結果を返す、 又は結果を返しつつ非同期処 理の状態を返さない 通常の値を返すメソッド。しかし 場合によっては非同期処理が走っ ているかもしれない void 同期処理で結果を返さない、 又は非同期処理で状態も結果 も返さない 通常の値を返さないメソッド。し かし場合によっては非同期処理が 走っているかもしれない
  5. 現実と設計(1) – 競合と回避 1 2 3 4 await await await

    継続処理用ワーカースレッド群 (スレッドプールから取得) awaitの前後で、処理スレッドが変わる (かもしれない)
  6. 現実と設計(1) – 競合と回避 1 2 3 4 await await await

    モニターロック取得スレッド モニターロック解放スレッド スレッドが一致していないので例外が発生
  7. 現実と設計(1) – 競合と回避 .NET標準(ハードウェイト) Nito.AsyncEx(非同期処理対応) Monitor, lockステートメント AsyncLock, AsyncMonitor Mutex

    AsyncLock Semaphore AsyncSemaphore ManualResetEvent AsyncManualResetEvent AutoResetEvent AsyncAutoResetEvent ReaderWriterLock AsyncReaderWriterLock しかし、そもそも排他制御を行って いると、オーバーヘッドでパフォー マンスが上がらないと言う問題があ ります(重要) 他にもSlim版(SemaphoreSlimなど)がありますが、ハードウェ イトのみないし、部分的に非同期に対応しているのみなので、 非同期処理には推奨しません Nito.AsyncExを使うと、非同期処理 で安全に排他制御できます
  8. 現実と設計(2) – GUIとスレッド 1 2 3 4 await await await

    ①がメインスレッド その他はワーカースレッド (?) ワーカースレッドで実行され たら例外で死ぬのでは?
  9. 現実と設計(2) – GUIとスレッド 1 2 3 4 await await await

    await後の処理を 「継続処理」と呼びます 継続処理 (1) 継続処理 (2) 継続処理 (3) コンソールアプリケーションと どう違うのか?
  10. 現実と設計(2) – GUIとスレッド 1 2 3 4 await await await

    デフォルトでは、継続処理の実行には、必ず ワーカースレッドが割り当てられます (メインスレッドとの区別はほとんどない) 継続処理 (1) 継続処理 (2) 継続処理 (3)
  11. 現実と設計(2) – GUIとスレッド 継続処理 (1) 継続処理 (2) 継続処理 (3) 1

    await await await WPFやWinFormsでは、継続処理の実行に、 常にメインスレッドが割り当てられます。 この制御を行っているのが、 SynchronizationContextの派生クラスです
  12. 現実と設計(2) – GUIとスレッド 1 2 3 4 await await await

    WPFデフォルトの挙動を無視し、以降は ワーカースレッドを割り当てるようになる もはや必ずワーカースレッドで実行されるので、 UIにアクセスする場合は、Dispatcherを使う必要があります
  13. 現実と設計(2) – GUIとスレッド 1 2 3 4 await await await

    ワーカースレッド間の転送は比較的 低コストなので、この間の継続処理 は実行効率が高くなる ここはメインスレッドに 転送するコストが高い
  14. 現実と設計(3) – 頻出パターン entry Text Text Text entry Text Text

    entry Text Text Text Text entry Text WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine 動きを振り返ってみます
  15. 現実と設計(3) – 頻出パターン entry Text Text Text entry Text Text

    entry Text Text Text Text entry Text foreachの2重ループ 逐次実行 WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine ChattyなUIへのアクセス (GUIの場合、ボトルネックになりうる)
  16. 現実と設計(3) – 頻出パターン entry Text Text Text entry Text Text

    entry Text Text Text Text entry Text WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine entry Text Text Text entry Text Text entry Text Text Text Text entry Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text WriteLine
  17. 現実と設計(3) – 頻出パターン entry Text Text Text entry Text Text

    entry Text Text Text Text entry Text WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine WriteLine entry Text Text Text entry Text Text entry Text Text Text Text entry Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text WriteLine LINQでそれぞれの Textを集約 Task.WhenAllで 全部の非同期 を集約 Task Task Task Task
  18. 現実と設計(3) – 頻出パターン entry Text Text Text entry Text Text

    entry Text Text Text Text entry Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text WriteLine Task Task Task Task 内側の処理をそれぞれ独立させて、 相互に依存しないようにします 並列実行性が高まります(安全) →モデル設計 M-(V-VM)
  19. 現実と設計(3) – 頻出パターン entry Text Text Text entry Text Text

    entry Text Text Text Text entry Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text WriteLine 全部の非同期処理を集約 するだけ 全部集約されてから、UIにアクセス 裏を返すと全部集約されないと UIにアクセスできない (トレードオフ)
  20. 現実と設計 Appendix ハードウェイト(ハードブロック) ◦ スレッドを(WindowsやLinuxなどのOSカーネルの機能で)一時停止させること。非同 期処理に対して、非互換。例外やデッドロックを引き起こす可能性があります。 ◦ Thread.Sleep(), Thread.Join() ◦

    Monitor.Enter() ◦ WaitHandle.WaitOne(), WaitHandle.WaitAny(), WaitHandle.WaitAll() ◦ Task.Wait(), Task.Result いつも言っていますが、ここまでの解説で、 上記は一切使っていません。 「Task.Wait(), Task.Resultは使いません・使えません・ 使う必要がありません!!」
  21. 追加された要素(2) – 非同期イテレーター データ群の処理方法 foreachによる逐次処理 Task.WhenAllによる集約処理 メリット 従来のループ手法をそのまま適用 できる。 出力やUIへの反映が逐次実行され

    る(インタラクティブ性・スト リーミング) 集合演算に根付く考え方に適合する なら、非常に直感的で高レベルな記 述が可能(LINQ)。 モデル設計として独立させやすい。 並列実行される。 デメリット 並列処理がやりにくい、あるいは そのままでは出来ない。 モデル設計として処理を完全に分 離することが難しい。 全てのデータが集約されてからしか、 結果にアクセスできない(配列)。
  22. 追加された要素(2) – 非同期イテレーター entry Text Text Text entry Text Text

    entry Text Text Text Text entry Text Text Text Text Text Text Text Text Text Text Text WriteLine Text Text Text Text Text Text Text
  23. 追加された要素(2) – 非同期イテレーター entry Text Text Text entry Text Text

    entry Text Text Text Text entry Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text WriteLine この部分を、データが得られたところ から逐次実行できないものか…
  24. 追加された要素(2) – 非同期イテレーター foreachによる逐次処理 Task.WhenAllによる集約処理 非同期イテレータを使う処理 メリット 従来のループ手法をそのま ま適用できる。 出力やUIへの反映が逐次実

    行される(インタラクティ ブ性・ストリーミング) 集合演算に根付く考え方に適 合するなら、非常に直感的で 高レベルな記述が可能 (LINQ)。 モデル設計として独立させや すい。 並列実行される。 従来のループ手法をそのまま適 用できる。 出力やUIへの反映が逐次実行さ れる(インタラクティブ性・ス トリーミング) モデル設計として独立させやす い。 デメリット 並列処理がやりにくい、あ るいはそのままでは出来な い。 モデル設計として処理を完 全に分離することが難しい。 全てのデータが集約されてか らしか、結果にアクセスでき ない(配列)。 並列処理がやりにくい、あるい はそのままでは出来ない。