Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
1. 非同期処理ってむずかしい (><)¶
Slide 2
Slide 2 text
1.1. はじめに¶ • C# 5.0から採用された • async / await • 手軽に非同期処理が書ける
Slide 3
Slide 3 text
1.2. わたし¶ おなまえ たむらかずひこ twitter ktz_alias • ひよっこC#使い (Lv.1) • gitムズ過ぎ • bzrかわいいよbzr
Slide 4
Slide 4 text
1.3. async の決まり事¶ • 戻り値がTaskまたはvoid • コード例は後で
Slide 5
Slide 5 text
1.4. async Task¶ • 完了するまで後続の処理を止めてくれる • その間は一旦、呼び出し元へ戻る • 呼び出し元で結果欲しい場合に使う
Slide 6
Slide 6 text
1.5. async Task¶ public async void Foo() { var bar = await BarAsync(); // 上の結果待ってから続行 return await BazzAsync(bar); } public async Task BarAsync() { ... }
Slide 7
Slide 7 text
1.6. async void¶ • 結果を待たず、呼び出し元に戻る • 投げっ放しジャーマン
Slide 8
Slide 8 text
1.7. async void¶ public async void Foo() { await BarAsync(); // 上の結果待たずに続行 await BazzAsync(); } public async void BarAsync() { ... }
Slide 9
Slide 9 text
1.8. await の決まり事¶ • asyncなメソッドでのみ使用可 • finally, catch, lock内では使用不可 • awaitableなメソッドにのみ付けれる
Slide 10
Slide 10 text
1.9. awaitableなメソッド?¶ • GetAwaiter() という名前のメソッド が定義された型 • そんな型を返すメソッド • Duck-Typing
Slide 11
Slide 11 text
1.10. awaitableなメソッド?¶ class Awatable { ... public Awaiter GetAwaiter() { } ... }
Slide 12
Slide 12 text
1.11. Awaiter?¶ • INotifyCompletionインターフェースを実装 • IsCompletedプロパティ • GetResultメソッド • まぁ...そんな型
Slide 13
Slide 13 text
1.12. Awaiter?¶ struct Awaiter : INotifyCompletion { public bool IsCompleted { get; } public T GetResult() {} // from INotifyCompletion void OnCompleted(Action k) {} }
Slide 14
Slide 14 text
1.13. 標準では...¶ System.Threading.Tasks • Task • Task
Slide 15
Slide 15 text
1.14. 標準では...¶ Windows.Foundation • IAsyncAction • IAsyncOperation • IAsyncActionWithProgress • IAsyncOperationWithProgress
Slide 16
Slide 16 text
1.15. 同期化¶ • await後に元のスレッドに戻ってくる • SynchronizationContextが有効 • ConfigureAwait(false)でも無効化
Slide 17
Slide 17 text
1.16. 同期化¶ • WinRTでは • WinRTSynchronizationContext
Slide 18
Slide 18 text
1.17. 同期化¶ 注意 • 直接Taskをインスタンス化した場合 • 同期化されません • STA前提のメソッドは死ぬ
Slide 19
Slide 19 text
1.18. async / awaitの内側¶ • コンパイラの中の人が • 継続渡し、状態遷移機械などの • 黒魔術を駆使して • 同期的な記述を非同期処理に変換
Slide 20
Slide 20 text
1.19. async / awaitの内側¶ ↓詳しくはココ http://blogs.msdn.com/b/ windowsappdev_ja/archive/ 2012/04/30/winrt-await.aspx
Slide 21
Slide 21 text
1.20. async / awaitでの苦労話¶ ココから本題
Slide 22
Slide 22 text
1.21. async / awaitでの苦労話¶ 1. 自前のTaskでawaitableなメソッド呼ぶ 結果 • 後続の実行前にTaskが完了する
Slide 23
Slide 23 text
1.22. async / awaitでの苦労話¶ await Task.Run(async () => { await FooAsync(); // ↓実行されない return await BarAsync(); });
Slide 24
Slide 24 text
1.23. async / awaitでの苦労話¶ どうする? • 解決方法なし • 直接作ったTask中の使用はあきらめましょう
Slide 25
Slide 25 text
1.24. async / awaitでの苦労話¶ 1. Linqと相性が悪い • Linq内でawaitすると • 戻り値がIEnumerable>
Slide 26
Slide 26 text
1.25. async / awaitでの苦労話¶ var r = sources.Select(async (s) => { return await BarAsync(s); });
Slide 27
Slide 27 text
1.26. async / awaitでの苦労話¶ • 値を取り出すために • foreachで回す必要があり
Slide 28
Slide 28 text
1.27. async / awaitでの苦労話¶ foreach (var task in results) { var result = await task; }
Slide 29
Slide 29 text
1.28. async / awaitでの苦労話¶ • よく訓練されたLinq使い • foreachを嫌う • Linqのうまみ半減
Slide 30
Slide 30 text
1.29. async / awaitでの苦労話¶ どうする? • Linqとawaitの併用はあきらめましょう
Slide 31
Slide 31 text
1.30. async / awaitでの苦労話¶ 1. Task.Wait()で死ねる • 同期コンテキスト有効で • 非同期処理連鎖の内側で呼ぶと • デッドロック
Slide 32
Slide 32 text
1.31. async / awaitでの苦労話¶ int Foo() { // ↓ 中でawaitするメソッド var task = BarAsync(); // ココでお見合い task.Wait(); return task.Result; }
Slide 33
Slide 33 text
1.32. async / awaitでの苦労話¶ • 同期化のために • なかのawaitが呼出し元を待つから ↓詳しくはココミテ http://blogs.msdn.com/b/pfxteam/ archive/2012/04/12/10293249.aspx
Slide 34
Slide 34 text
1.33. async / awaitでの苦労話¶ どうする? • あきらめま(ry
Slide 35
Slide 35 text
1.34. async / awaitでの苦労話¶ 1. ならばと、GetAwaiter().GetResult()で無理矢理呼ぶ
Slide 36
Slide 36 text
1.35. async / awaitでの苦労話¶ public async void Foo() { var task = BarAsync(); task.GetAwaiter().GetResult(); }
Slide 37
Slide 37 text
1.36. async / awaitでの苦労話¶ • 結果 • はい、デッドロック
Slide 38
Slide 38 text
1.37. async / awaitでの苦労話¶ どうする? • あ(ry
Slide 39
Slide 39 text
1.38. async / awaitでの苦労話¶ 1. Parallel.Foreachの中では使えない
Slide 40
Slide 40 text
1.39. async / awaitでの苦労話¶ Paralle.Foreach(list, async (x) => { await Foo(x); }); • すべてのアクション完了まで待ってほしいのに... • Task.Run同様、投げっ放しジャーマン
Slide 41
Slide 41 text
1.40. async / awaitでの苦労話¶ どうする? • 気合いで非同期版作って下さい ↓ココミテ http://blogs.msdn.com/b/pfxteam/ archive/2012/03/04/10277325.aspx
Slide 42
Slide 42 text
1.41. async / awaitでの苦労話¶ 1. ユニットテストしづらい • NUnitはasync / await未対応 • 何も考えず走らせると • テストが実行されず終了(CLI版)
Slide 43
Slide 43 text
1.42. async / awaitでの苦労話¶ どうする?
Slide 44
Slide 44 text
1.43. async / awaitでの苦労話¶ CUI Runnerの場合 • 同期化されていないので • Taskk.Wait() or GetAwaiter().GetResult()で待たせる
Slide 45
Slide 45 text
1.44. async / awaitでの苦労話¶ public void RunTest(Func inTest) { inTest.GetAwaiter().GetResult(); } [Test] public void _TestSomething() { RunTest(async () => { ... }); }
Slide 46
Slide 46 text
1.45. async / awaitでの苦労話¶ GUI Runnerの場合 • 自前の同期コンテキストを気合いで実装 • 割と安定してる • けどグローバルな存在なので、ほかでこっそり使われると死ねる
Slide 47
Slide 47 text
1.46. WinRTのハマりどころ¶ • Windowsストアアプリ作成のためのAPIセット • 非同期処理を多用 • async / awaitの知識必須
Slide 48
Slide 48 text
1.47. Windowsストアアプリ¶ • Met(検閲により削除)... • とか言うと • MSの方から来た人に手招きされるかもなので注意
Slide 49
Slide 49 text
1.48. WinRTでの苦労話¶ 1. Windows.Storage APIの使用 スレッドまたいで使用するとSIBOU ArgumentException 範囲外です • (何が?) COMException その他のエラー • (追跡不能)
Slide 50
Slide 50 text
1.49. WinRTでの苦労話¶ STAの制約っぽい • スレッドをまたがない • 再取得すると問題出ない
Slide 51
Slide 51 text
1.50. WinRTでの苦労話¶ 1. BackgroundTask • awaitすると • 戻ってくる前に完了状態になっちゃう
Slide 52
Slide 52 text
1.51. WinRTでの苦労話¶ どうする? • defferalを取得しておけば待ってくれる • GetDefferal() • 終わったらdefferalのComplete()呼ぶ
Slide 53
Slide 53 text
1.52. WinRTでの苦労話¶ 1. BackgroundTask スレッドの生成がアプリ本体とは異なる。 • メインスレッドがParallel#ForEachの中に入ってきた。
Slide 54
Slide 54 text
1.53. WinRTでの苦労話¶ 1. BackgroundTask • 中でTask.Wait()してしまっていたので • デッドロックした • /(^o^)\
Slide 55
Slide 55 text
1.54. まとめ¶ • C# 5.0で非同期処理が手軽に使えるようになった • けど...ハマりどころ多数 • まぁ、まるちすれっどですゆえ
Slide 56
Slide 56 text
1.55. まとめ¶ (・ワ・)