Slide 1

Slide 1 text

パターンでわかる! .NET Coreの 非同期処理 2019.10.5 .NET CONF 2019 MEETUP IN AICHI - KOUJI MATSUI (@KOZY_KEKYO, @KEKYO2)

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

Agenda .NET Core 3とC# 8.0で完成した.NET非同期処理 .NET非同期処理のおさらい .NET非同期処理の現実と設計 追加された非同期処理の要素

Slide 4

Slide 4 text

What’s new features 本日は、以下のことをお話します: .NET非同期処理のおさらい ◦ 概要と基本的な書き方 ◦ コンソールアプリケーションとGUIアプリケーションとの違い ◦ お勧めしたいプラクティスとアンチパターン .NET非同期処理の現実と設計 ◦ 現実的なアプリケーションへの適用と課題 追加された非同期処理の要素 ◦ 足りなかったもの・足りていると勘違いされていたもの

Slide 5

Slide 5 text

What’s new features .NET Core 3とC# 8.0で、.NETの非同期処理はついに完成 Task async-await ValueTask IAsyncEnumerable Awaitable foreach 世 代

Slide 6

Slide 6 text

What’s new features .NET Core 3とC# 8.0で、.NETの非同期処理はついに完成 Task async-await ValueTask IAsyncEnumerable Awaitable foreach .NET Core 3 世 代

Slide 7

Slide 7 text

What’s new features .NET Core 3とC# 8.0で、.NETの非同期処理はついに完成 Task async-await ValueTask IAsyncEnumerable Awaitable foreach 非同期処理記述の 容易さの壁 (1) 非同期処理記述の 容易さの壁 (2) 世 代 今日は、壁より前の話や内部の話はしません。 なぜ非同期で処理を行う必要があるのかについては、 「Async訪ねて3000里」を参照

Slide 8

Slide 8 text

.NET非同期処理のおさらい 非同期処理、ポイントを押さえれば難しくありません。なの に、正しく書けてない、場合によっては危険なコードが散見さ れます。 .NET Core 3とC# 8.0で劇的に便利になったので、そろそろマス ターしちゃいましょう! 非同期処理を記述する際に遭遇する問題のパターンと、解決 の方策を示します。

Slide 9

Slide 9 text

基本的な操作(1) – ファイルアクセス コンソールアプリケーションで非同期処理してみる ファイル出力を非同期処理で書いてみる

Slide 10

Slide 10 text

基本的な操作(1) – ファイルアクセス 任意のデータを ファイルに出力する FileAccessWithAsync.csproj

Slide 11

Slide 11 text

基本的な操作(1) – ファイルアクセス 注目すべきポイント

Slide 12

Slide 12 text

基本的な操作(1) – ファイルアクセス I/O操作はすべて(Taskを返却する) 非同期対応メソッドを使用してawaitする

Slide 13

Slide 13 text

基本的な操作(1) – ファイルアクセス メソッド中でawaitを使う場合は、メソッド 宣言でasyncとマークし、Taskを返す

Slide 14

Slide 14 text

基本的な操作(1) – ファイルアクセス C# 7.1から、Mainメソッドが Taskを返せるようになった

Slide 15

Slide 15 text

基本的な操作(1) – ファイルアクセス FileStreamクラス固有: falseまたは省略した場合は、 非同期I/Oはワーカースレッド によるシミュレート

Slide 16

Slide 16 text

ファイルアクセス Appendix ファイルアクセスでよく使われる Fileクラスのメソッド

Slide 17

Slide 17 text

ファイルアクセス Appendix Task.Runを使って、ワーカースレッドでシ ミュレートするのと同じなので、非効率

Slide 18

Slide 18 text

ファイルアクセス Appendix Mainメソッドの対処方法: C#7.0以前を使う場合は、このように非同期 メソッドにバイパスする (但しコンソールアプリケーションのみ)

Slide 19

Slide 19 text

基本的な操作(2) – 独立した非同期処理 非同期処理を行うメソッドを作る 非同期処理を行うクラスライブラリを作る

Slide 20

Slide 20 text

基本的な操作(2) – 独立した非同期処理 指定されたURLからJSON形式 のデータをダウンロードして パースするライブラリ IndependentLibrary.csproj

Slide 21

Slide 21 text

基本的な操作(2) – 独立した非同期処理 注目すべきポイント

Slide 22

Slide 22 text

基本的な操作(2) – 独立した非同期処理 メソッド中でawaitを使う場合は、メソッド 宣言でasyncとマークする

Slide 23

Slide 23 text

基本的な操作(2) – 独立した非同期処理 メソッド内部で非同期処理を行い、結果 を値として返すので、Task型とする

Slide 24

Slide 24 text

基本的な操作(2) – 独立した非同期処理 Task又はTaskを返す場合に、 メソッド名末尾にAsyncをつける (必須ではないが強く推奨) `async`とマークした場合、 ではないことに注意

Slide 25

Slide 25 text

独立した非同期処理 Appendix 末尾にAsyncとつける推奨について: 1. 末尾にAsyncとついていれば、使用者が非同期処理対応の メソッドを容易に見分けられる(インテリセンスを活用 する意味でも重要) 2. よく見られる誤ったプラクティス: `async`とマークした場 合に、メソッド名末尾にAsyncと付ける… → TaskやTaskを返した場合に、末尾にAsyncを付ける Streamクラスのメンバー一覧

Slide 26

Slide 26 text

独立した非同期処理 Appendix 抽象度の高いインターフェイス定義。 メソッドは値を返さない 誤ったプラクティスと考える理由 InterestingService.csproj

Slide 27

Slide 27 text

独立した非同期処理 Appendix 共通のインターフェイスメソッドを 実装し、ログを出力する

Slide 28

Slide 28 text

独立した非同期処理 Appendix ログ出力の負荷を軽減するため、バックグラ ウンドで出力するように改良。 呼び出し元はログがバックグラウンドで出力 されているかどうかを気にしなくても良い (=通知手段がないので出来ない)

Slide 29

Slide 29 text

独立した非同期処理 Appendix ウェブサービスに アクセスする実装

Slide 30

Slide 30 text

独立した非同期処理 Appendix メソッド中でawaitを使う場合は、メソッド 宣言でasyncとマークする

Slide 31

Slide 31 text

独立した非同期処理 Appendix `async`とマークしているが、 末尾にAsyncと命名できない… `async`のマークは、内部でawaitキーワードを使っ たかどうかであって、非同期処理をするかどうか (インターフェイスの規定)とは関係がない

Slide 32

Slide 32 text

独立した非同期処理 Appendix このメソッドは、同期的に値を返さない。 内部の処理は同期的に行われているかもしれないし、非同期的に行われて いるかもしれない(わからない)。 非同期的に行われているのであれば、その結果を知ることは出来ない。 このインターフェイスメソッドの 真の意味

Slide 33

Slide 33 text

WPFやWinFormsで非同期処理をおこなう 基本的な操作(3) – GUI内での操作

Slide 34

Slide 34 text

基本的な操作(3) – GUI内での操作 ボタンが押されたら ファイルを生成する WPFアプリケーション WpfAppWithAsync.csproj

Slide 35

Slide 35 text

基本的な操作(3) – GUI内での操作 注目すべきポイント

Slide 36

Slide 36 text

基本的な操作(3) – GUI内での操作 メソッド中でawaitを使う場合は、メソッド 宣言でasyncとマークする

Slide 37

Slide 37 text

基本的な操作(3) – GUI内での操作 イベントハンドラの戻り値をTaskにする ことは出来ない。その場合、voidだけが 非同期メソッドとして許される

Slide 38

Slide 38 text

基本的な操作(3) – GUI内での操作 イベントハンドラの戻り値を Taskにすることは出来ない

Slide 39

Slide 39 text

基本的な操作(3) – GUI内での操作 メソッド名末尾にAsyncと付けるプラクティスの背景と 同じことが、イベントハンドラについても言えます このメソッドは、同期的に値を返さない。 内部の処理は同期的に行われているかもしれないし、非同期的に行われて いるかもしれない(わからない)。 非同期的に行われているのであれば、その結果を知ることは出来ない。

Slide 40

Slide 40 text

基本的な操作 Appendix 戻り値の型 直接的な意味 処理の詳細 Task 非同期処理を行いT型の結果 を返す 非同期処理を行い、処理完了後に 結果を値として返す Task 非同期処理を行い結果を返さ ない 非同期処理を行い、処理完了後に 完了したことだけが通知される T 同期処理でT型の結果を返す、 又は結果を返しつつ非同期処 理の状態を返さない 通常の値を返すメソッド。しかし 場合によっては非同期処理が走っ ているかもしれない void 同期処理で結果を返さない、 又は非同期処理で状態も結果 も返さない 通常の値を返さないメソッド。し かし場合によっては非同期処理が 走っているかもしれない

Slide 41

Slide 41 text

.NET非同期処理の現実と設計 ここまでで、基本的な非同期処理の実装の方法を再確認して きました。 この節では、現実に発生しうる問題について、もう少し掘り 下げます。

Slide 42

Slide 42 text

現実と設計(1) – 競合と回避 非同期処理中に競合条件が発生する場合、その回避方法を確 認します。 回避方法は非同期処理特有で、従来の手法が通用しないこと を知ってください。

Slide 43

Slide 43 text

現実と設計(1) – 競合と回避 100回実行(つまり、100回インクリメント されるはず) RaceConditionWithAsync.csproj ファイル内の数値文字列を インクリメントして ファイルに書き戻す

Slide 44

Slide 44 text

現実と設計(1) – 競合と回避 非同期処理 Task.WhenAllで、100個のTaskを 並列実行することになる

Slide 45

Slide 45 text

現実と設計(1) – 競合と回避 100にならない… → 排他処理を何もしていないので、 競合が発生している

Slide 46

Slide 46 text

現実と設計(1) – 競合と回避 awaitを使っていると、lockステートメントで モニターロックは出来ない (C#コンパイルエラー) モニターロック(ミューテックス)で 競合を回避したい、が…

Slide 47

Slide 47 text

現実と設計(1) – 競合と回避 モニターロックを手動で構成…

Slide 48

Slide 48 text

現実と設計(1) – 競合と回避 SynchronizationLockException: モニターロックが異なるスレッドで 解除されようとしている

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

現実と設計(1) – 競合と回避 1 2 3 4 await await await モニターロック取得スレッド モニターロック解放スレッド スレッドが一致していないので例外が発生

Slide 51

Slide 51 text

現実と設計(1) – 競合と回避 つまりこの方法は根本的にダメ。 C#コンパイラが親切にlockを 使わせないようにしている

Slide 52

Slide 52 text

現実と設計(1) – 競合と回避 NuGetパッケージ: Nito.AsyncEx Stephen Cleary氏の作品 ほぼlockステートメントと同じように使えて、 非同期処理対応(排他待機をawait出来る)

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

現実と設計(2) – GUIとスレッド GUIアプリケーションで非同期処理を行う場合は、コンソー ルアプリケーションとは異なる動きをします。 なぜ、GUIアプリケーションでは非同期処理が強く推奨され るのか、について掘り下げます。

Slide 55

Slide 55 text

現実と設計(2) – GUIとスレッド ボタンが押されたら ファイル内の数値文字列を インクリメントする WPFアプリケーション WpfAppRaceConditionWithAsync.csproj

Slide 56

Slide 56 text

現実と設計(2) – GUIとスレッド GUIアプリケーションでも 非同期処理は普通に使える

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

現実と設計(2) – GUIとスレッド こう書くべき?? いいえ、Dispatcherを使ってメインスレッドに 明示的に転送しなくても問題ありません! なぜならば…

Slide 59

Slide 59 text

現実と設計(2) – GUIとスレッド 1 await await await 実際にはメインスレッドしか 使われないからです!! メインスレッドで実行される

Slide 60

Slide 60 text

現実と設計(2) – GUIとスレッド 1 await await await 根本的な疑問「なぜ非同期処理をGUIアプリケー ションに適用すると、ユーザーインターフェイス が固まらないのですか?」

Slide 61

Slide 61 text

現実と設計(2) – GUIとスレッド 1 await await await awaitすると、メインスレッドは一時的にApplication.Run()の内部に戻ること が出来て、非同期処理が完了するまでは、別のイベントを処理できます (ボタンクリックイベント処理や、描画処理など) Application.Run() OnClick OnRender Application.Run() Application.Run()

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

現実と設計(2) – GUIとスレッド いつもメインスレッドが継続処理を実行 しているとしたら、こうやって書いてい るのと同じようなものでは? (つまり、遅いのでは?) (厳密には違うのですが) パフォーマンスの懸念がある点では その通りです…

Slide 66

Slide 66 text

現実と設計(2) – GUIとスレッド そこで、ConfigureAwait()を使います await await await 1

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

現実と設計(2) – GUIとスレッド 1 2 3 4 await await await ワーカースレッド間の転送は比較的 低コストなので、この間の継続処理 は実行効率が高くなる ここはメインスレッドに 転送するコストが高い

Slide 69

Slide 69 text

現実と設計(3) – 頻出パターン 非同期処理には、特有のパターンがあります。 うまくこのパターンに当てはめれば、高効率かつ劇的に簡単 に実装できるようになります。 競合と排他を避けるためにも、このパターンに乗せてくださ い。

Slide 70

Slide 70 text

現実と設計(3) – 頻出パターン XMLデータをダウンロードして パースする 非同期パース対応(.NET Core 3から) AggregateThingsWithAsync.csproj

Slide 71

Slide 71 text

現実と設計(3) – 頻出パターン 気象庁防災情報 XMLフォーマット形式電文 (中身はAtomフィード)

Slide 72

Slide 72 text

現実と設計(3) – 頻出パターン Atomフィードのエントリn個を

Slide 73

Slide 73 text

現実と設計(3) – 頻出パターン ダウンロードしてパースし、

Slide 74

Slide 74 text

現実と設計(3) – 頻出パターン コメントを抽出する

Slide 75

Slide 75 text

現実と設計(3) – 頻出パターン 2重ループ

Slide 76

Slide 76 text

現実と設計(3) – 頻出パターン ループといえばLINQ

Slide 77

Slide 77 text

現実と設計(3) – 頻出パターン 最初のAtomフィードの ダウンロードは同じ

Slide 78

Slide 78 text

現実と設計(3) – 頻出パターン 内側のループに注目して、Task を返すメソッドやラムダ式に する

Slide 79

Slide 79 text

現実と設計(3) – 頻出パターン 非同期ラムダブロック: Task

Slide 80

Slide 80 text

現実と設計(3) – 頻出パターン XML LINQ

Slide 81

Slide 81 text

現実と設計(3) – 頻出パターン Task.WhenAllで、複数のTaskを一度に 非同期待機する

Slide 82

Slide 82 text

現実と設計(3) – 頻出パターン 並列実行され、 やがて結果がまとめて返される

Slide 83

Slide 83 text

現実と設計(3) – 頻出パターン 結果を全て出力

Slide 84

Slide 84 text

現実と設計(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 動きを振り返ってみます

Slide 85

Slide 85 text

現実と設計(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の場合、ボトルネックになりうる)

Slide 86

Slide 86 text

現実と設計(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

Slide 87

Slide 87 text

現実と設計(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

Slide 88

Slide 88 text

現実と設計(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)

Slide 89

Slide 89 text

現実と設計(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にアクセスできない (トレードオフ)

Slide 90

Slide 90 text

現実と設計 Appendix 補足

Slide 91

Slide 91 text

現実と設計 Appendix ハードウェイト(ハードブロック) ◦ スレッドを(WindowsやLinuxなどのOSカーネルの機能で)一時停止させること。非同 期処理に対して、非互換。例外やデッドロックを引き起こす可能性があります。 ◦ Thread.Sleep(), Thread.Join() ◦ Monitor.Enter() ◦ WaitHandle.WaitOne(), WaitHandle.WaitAny(), WaitHandle.WaitAll() ◦ Task.Wait(), Task.Result いつも言っていますが、ここまでの解説で、 上記は一切使っていません。 「Task.Wait(), Task.Resultは使いません・使えません・ 使う必要がありません!!」

Slide 92

Slide 92 text

現実と設計 Appendix 非同期処理(待機可能・Awaitable) ◦ 実行単位をスレッドではなく、抽象的なタスクとみなし、タスクを一 時停止させる。タスクを実行するのはスレッドですが、特定のタスク がいつも特定のスレッドで実行されるとは限りません。 ◦ Task.Delay() ◦ Stream.ReadAsync(), Stream.WriteAsync() ◦ TextReader.ReadLineAsync(), TextWriter.WriteLineAsync() ◦ HttpClient.GetAsync(), HttpClient.PostAsync() 上記は全てTask又はTaskを返します。

Slide 93

Slide 93 text

現実と設計 Appendix ハードウェイトを行うメソッドを非同期処理と混ぜて安全に (かつパフォーマンスを最大化して)使用するのは、トップレ ベルの技術者でも非常に困難です(あるいは不可能)。 つまり、やりたくなったら 何かが間違っています いやでも今自分が遭遇している問題は、当てはまらない レアケースだから… と言っている問題も間違いです

Slide 94

Slide 94 text

追加された非同期処理の要素 ValueTaskはTaskのメモリ確保コストを削減します。 非同期イテレーターインターフェイスが、標準定義され、非 同期イテレーターを列挙する構文・列挙可能にする構文が、 C#8.0で追加されました。 非同期イテレーターを活用すれば、モデル実装がより簡単に なります。

Slide 95

Slide 95 text

追加された非同期処理の要素(1) – ValueTask ValueTaskをTaskの代わりに使っていきたい動機について。 なぜ効率が良いのか?

Slide 96

Slide 96 text

追加された要素(1) – ValueTask ValueTaskはTaskの構造体版

Slide 97

Slide 97 text

追加された要素(1) – ValueTask AggregateThingsWithAsync.csproj

Slide 98

Slide 98 text

追加された要素(1) – ValueTask 1. Taskで宣言していたところを機械的にValueTaskに置 き換え出来る。 2. Taskで出来ることはValueTaskでもだいたいできる。 3. ValueTask.AsTask()を呼び出せばTaskに変換できる。 ValueTask.WhenAllはないが、Taskを 返す非同期処理を混ぜて使える

Slide 99

Slide 99 text

何が嬉しいの? ◦ もし、非同期処理がその場で完了した場合(たとえば、ReadLineAsync() の読み取りがバッファリングされていたデータなどで直ぐに返せるな ど)、TaskだとTaskクラスのインスタンス生成にコストが掛かるけど、 ValueTaskならほとんどコストがかからない(構造体だから) ◦ 非同期待機が実際に発生する場合に、初めて内部でTaskのインスタンス が生成される。 追加された要素(1) – ValueTask

Slide 100

Slide 100 text

つまり? async-await構文でawaitしまくるコードを書いた場合: ◦ Taskだとawaitの度にTaskのインスタンスが生成されるので、効率が悪い ◦ ValueTaskだと結果が直ぐに得られる場合は、インスタンス生成コスト が発生しない 追加された要素(1) – ValueTask 注意: ValueTaskを使う場合は、 System.Threading.Tasks.Extensions パッケージを追加する必要があります

Slide 101

Slide 101 text

追加された要素(2) – 非同期イテレーター Task.WhenAllが配列を返す件。 yield returnを非同期処理と組み合わせて使えます。

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

追加された要素(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

Slide 104

Slide 104 text

追加された要素(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 この部分を、データが得られたところ から逐次実行できないものか…

Slide 105

Slide 105 text

AggregateThingsWithAsync.csproj 追加された要素(2) – 非同期イテレーター

Slide 106

Slide 106 text

追加された要素(2) – 非同期イテレーター IAsyncEnumerableで、列挙可能で かつ非同期処理を実現できる

Slide 107

Slide 107 text

追加された要素(2) – 非同期イテレーター 普通にawaitできる

Slide 108

Slide 108 text

追加された要素(2) – 非同期イテレーター IEnumerableと同じように、 yield returnで要素を返せる

Slide 109

Slide 109 text

追加された要素(2) – 非同期イテレーター 実装の詳細が外部に漏れていない、 真に独立したモデルメソッドを実現

Slide 110

Slide 110 text

追加された要素(2) – 非同期イテレーター 非同期イテレーターは、 新しいawait foreachという構文で、 非同期的に列挙できる

Slide 111

Slide 111 text

追加された要素(2) – 非同期イテレーター awaitを付けたからasyncを忘れずに

Slide 112

Slide 112 text

追加された要素(2) – 非同期イテレーター 非同期イテレーターとは? ValueTaskを使う。 つまり、連続してすぐに値を返せる場合は、 Taskよりもコストが低い

Slide 113

Slide 113 text

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

Slide 114

Slide 114 text

Any question? Thank you for join!! スライドのコードは全てここにあります: https://github.com/kekyo/dotnetconf2019

Slide 115

Slide 115 text

Any question? Thank you for join!! https://github.com/kekyo/dotnetconf2019