C#次世代非同期処理概観 - Task vs Reactive Extensions

39,115 views

Published on

RIA アーキテクチャー研究会 第3回
http://atnd.org/events/24951

Published in: Technology
0 Comments
28 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
39,115
On SlideShare
0
From Embeds
0
Number of Embeds
22,864
Actions
Shares
0
Downloads
113
Comments
0
Likes
28
Embeds 0
No embeds

No notes for slide

C#次世代非同期処理概観 - Task vs Reactive Extensions

  1. 1. C#次世代非同期処理概観Task vs Reactive Extensions 2012/3/10 #riaarch Yoshifumi Kawai @neuecc
  2. 2. Profile Name => Yoshifumi Kawai  仕事は近頃はASP.NETで、あまりRIAじゃなかったり  まあ、HTML5もRIAですし! Twitter => @neuecc HN => neuecc  読むときは“のいえ”と読ませてます  サイトのドメイン(特に意味はない)を繋いだだけ で、識別子になればそれだけでいいと思って発音考 えてなかったので割とアレ  Microsoft MVP for Visual C#(2011/4-)
  3. 3. サイト http://neue.cc/ C#とかLINQ 配色がアレ
  4. 4. linq.js http://linqjs.codeplex.com/ LINQのJavaScript移植
  5. 5. ReactiveProperty http://reactiveproperty.codeplex.com/ Rxスタイルのバインディング補助ライブラリ .NET4/SL5/SL5/WP7.1 対応
  6. 6. Agenda 非同期処理とは何か 非同期処理の苦痛 .NET Frameworkにおける非同期処理パターン C# 5.0(Visual Studio 11)の非同期処理(async/await) Task vs Rx
  7. 7. What is asynchronous?
  8. 8. 非同期って? Parallel?  並列 - 一つの処理をバラして同時実行して高速化  Parallel.For/Parallel.ForEach/Parallel LINQ Concurrent?  並行 - 個別な処理が相互作用したりしなかったり  Thread, Task Asynchronous!  非同期 - ブロックしない処理  UIスレッドを止めなかったりIO処理効率化だったり  DownloadStringAsyncなどやBeginXxx-EndXxxなど  ThreadやTaskを使っても勿論いい
  9. 9. 非同期はなぜ重要か 「クラウド」並のバズワード、とか言ってみたり RIA的にはUIスレッドのブロックいくない  ユーザーエクスペリエンス的には当然だろ常考  Silverlight, Windows Phone, Windows 8(WinRT)には最 初から非同期メソッドしか用意されていない(同期 処理不可!)  JavaScriptなんて最初からそれOnlyですしね Web的には同時接続対策  C10K問題  http://www.hyuki.com/yukiwiki/wiki.cgi?TheC10kProblem  node.jsの流行にC#erとしてはC# 5.0で対抗する!
  10. 10. Demo
  11. 11. Asynchronous Blues
  12. 12. ネスト宇宙ヤバイ 単発ならそれほどでもない ネストすると人類の手に負えないvar wc = new WebClient();wc.DownloadStringCompleted += (_, res) =>{ var wc2 = new WebClient(); wc2.DownloadStringCompleted += (__, res2) => { MessageBox.Show(res2.Result); }; wc2.DownloadStringAsync(new Uri(res.Result));};wc.DownloadStringAsync(newUri("http://localhost:8403/TestAPI.ashx"));
  13. 13. 例外処理不能 というかもう無理。var wc = new WebClient();wc.DownloadStringCompleted += (_, res) =>{ if (res.Error != null) { MessageBox.Show(res.Error.Message); } var wc2 = new WebClient(); wc2.DownloadStringCompleted += (__, res2) => { if (res2.Error != null) { MessageBox.Show(res2.Error.Message); } MessageBox.Show(res2.Result); }; wc2.DownloadStringAsync(new Uri(res.Result));};wc.DownloadStringAsync(new Uri("http://localhost:8403/TestAPI.ashx"));
  14. 14. Patterns of Async Operation
  15. 15. APMとは Asynchronous Programming Model BeginXxx-EndXxxのペアによる非同期処理 WebRequest#BeginGetResponse-EndGetResponse のようなもの とにかく面倒くさい  ラムダ式登場で割と緩和されたけれど 正しく使うのは慣れが必要 後述するTaskやRxのベースとして活躍 .NETにおけるもっともプリミティブな非同期シス テムと考えていただければ
  16. 16. var req = WebRequest.Create("http://localhost:8403/TestAPI.ashx");req.BeginGetResponse(ar => 非同期処理中の例外はEndのタイミングで伝送{ try { var res = req.EndGetResponse(ar); var req2 = WebRequest.Create(new StreamReader(res.GetResponseStream()).ReadToEnd()); req2.BeginGetResponse(ar2 => { UIスレッドへ通達する必要がある try { var res2 = req2.EndGetResponse(ar2); var result = new StreamReader(res2.GetResponseStream()).ReadToEnd(); Dispatcher.BeginInvoke(() => MessageBox.Show(result)); } catch (Exception ex2) { Dispatcher.BeginIncoke(()=> MessageBox.Show("inner error " + ex2.Message)); } }, null); } catch (Exception ex1) catchできるのは同じ関数のブロック内だけ { Dispatcher.BeginIncoke(()=> MessageBox.Show("outer error " + ex1.Message)); }}, null);
  17. 17. EAPとは Event-BasedAsynchronous Pattern XxxAsyncメソッド + XxxCompletedイベントのペア による非同期処理 WebClient#DownloadStringAsyncのようなもの 素の状態のC#では割と楽な書き方 リクエストの発行が後になるという順序の問題を 抱える 後述するTaskやRxの登場でサヨウナラ行き TaskやRxでラップするのも面倒くさいという
  18. 18. UIスレッドまわりは自動で面倒var wc = new WebClient();wc.DownloadStringCompleted += (_, res) => みてくれる(WebClientの場合){ if (res.Error != null) { MessageBox.Show(res.Error.Message); } var wc2 = new WebClient(); wc2.DownloadStringCompleted += (__, res2) => { if (res2.Error != null) { 先にイベントを登録して MessageBox.Show(res2.Error.Message); } MessageBox.Show(res2.Result); }; wc2.DownloadStringAsync(new Uri(res.Result));};wc.DownloadStringAsync(new Uri("http://localhost:8403/TestAPI.ashx")); リクエストの発行は後で行う(順序が逆だとダメ!)
  19. 19. TAPとは TaskBased Asynchronous Pattern .NET 4/SL5以降登場したTPLを使った非同期処理  TPLはTask Parallel Libraryの略  Threadを概ね置き換えます Task.Factory.FromAsyncでAPMをラップ .NET 4.5やWinRTにはフレームワークに最初から ラップ済み or TAP用に書かれた専用メソッドが大 量追加  WebRequest#GetResponseAsyncとか  WebClient#DownloadStringAsyncとか
  20. 20. UIスレッド用スケジューラを用意することで 個別BeginInvoke不要var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); APMをラップするvar req = WebRequest.Create("http://localhost:8403/TestAPI.ashx");Task.Factory.FromAsync<WebResponse>(req.BeginGetResponse, req.EndGetResponse, null) .ContinueWith(res => { var req2 = WebRequest.Create(new StreamReader(res.Result.GetResponseStream()).ReadToEnd()); return Task.Factory.FromAsync<WebResponse>(req2.BeginGetResponse, req2.EndGetResponse, null); }) .Unwrap() .ContinueWith(res => ネストしたTaskは明示的にUnwrap { MessageBox.Show(new StreamReader(res.Result.GetResponseStream()).ReadToEnd()); }, uiScheduler) .ContinueWith(res => { MessageBox.Show(res.Exception.Message); }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, uiScheduler);階層構造はフラット 例外は最後に統一的処理が可能
  21. 21. Rxとは Reactive Extensions  http://msdn.microsoft.com/en-us/devlabs/gg577609 LINQベースのイベント・非同期処理ライブラリ LINQ to Events, LINQ to Asynchronous WP7には同梱、JavaScript版もあり @ITで連載やってるので読んでね!  http://www.atmarkit.co.jp/fdotnet/introrx/index/index. html LINQベースのため合成処理が異常なほど強力 非同期処理だけではなくあらゆる用途に使える
  22. 22. APMをラップするvar req = WebRequest.Create("http://localhost:8403/TestAPI.ashx");Observable.FromAsyncPattern<WebResponse>(req.BeginGetResponse, req.EndGetResponse)() .SelectMany(res => { var next = new StreamReader(res.GetResponseStream()).ReadToEnd(); var req2 = WebRequest.Create(next); return Observable.FromAsyncPattern<WebResponse>(req2.BeginGetResponse, req2.EndGetResponse)() }) .ObserveOnDispatcher() 実行スレッドのコントロール .Subscribe( res => MessageBox.Show(new StreamReader(res.GetResponseStream()).ReadToEnd()), ex => MessageBox.Show(ex.Message)); 例外は最後に統一的処理が可能 階層構造はフラット
  23. 23. // Taskもそうですが、ラップ用メソッドは事前に拡張メソッドを作っておくと良いです public static class WebRequestExtensions { public static IObservable<WebResponse> GetResponseAsObservable(this WebRequest request) { return Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetRespo } public static IObservable<string> DownloadStringAsObservable(this WebRequest request) { return request.GetResponseAsObservable() .Select(res => { using (var sr = new StreamReader(res.GetResponseStream())) { return sr.ReadToEnd(); } }); 非同期処理とは思えないほど超 } } 絶的に本体がシンプルになる事前にラップ用拡張メソッドを用意すると WebRequest.Create("http://localhost:8403/TestAPI.ashx") .DownloadStringAsObservable() .SelectMany(x => WebRequest.Create(x).DownloadStringAsObservable()) .ObserveOnDispatcher() .Subscribe( x => MessageBox.Show(x), ex => MessageBox.Show(ex.Message));
  24. 24. Future
  25. 25. C# 5.0 Visual Studio 11  http://www.microsoft.com/visualstudio/11/ja-jp async/await構文でContinueWithが言語サポート それに加えて標準クラスライブラリにもラップ済 みor専用処理のXxxAsync/XxxTaskAsyncメソッドが 大量追加  ライブラリはWinRT/.NET 4.5のみでSL5やWP7には現 在はなし  async/await自体は可能なので、自分でラップを作っ て拡張メソッドとして用意すればいい
  26. 26. asyncキーワードを足すprivate async void Button_Click_1(object sender, RoutedEventArgs e){ try { var nextUrl = await new WebClient().DownloadStringTaskAsync("http://localhost:8403/TestAPI.as var result = await new WebClient().DownloadStringTaskAsync(nextUrl); MessageBox.Show(result); } catch (Exception ex) { awaitキーワードで継続 MessageBox.Show(ex.Message); }} 同期構文と何も変わらない例外処理
  27. 27. Rx is awaitable  Task vs RxだったらRxのほうが使いやすい  ただしC# 5.0ではTaskが圧倒的に使いやすい  じゃあ将来を見据えてTaskで作ったほうが……?  Rx(IObservable<T>)もawaitさせることはできます  現在は実験版リリース or ver.2 Betaのみ対応var nextUrl = await WebRequest.Create("http://localhost:8403/TestAPI.ashx").DownloadStringAsObservablvar result await WebRequest.Create(nextUrl).DownloadStringAsObservable()
  28. 28. Task is Observable TaskのメソッドはToObservableでRxに変換可能 SelectManyなど一部の主要なRxの合成系メソッド はTaskを直接渡すことに対応  まだ実験版, Rx v2 Betaのみnew WebClient().DownloadStringTaskAsync("url").ToObservable() .SelectMany(x => new WebClient().DownloadStringTaskAsync(x)) .Subscribe()
  29. 29. FromAsyncPattern Rxはawait可能であること、C# 5.0でTaskベースの 非同期処理がライブラリレベルでも主流になるこ とから、Rx v2ではObservable.FromAsyncPatternは Obsolete(非推奨)となりました Task.FromAsyncを使い、必要ならばToObservable していく
  30. 30. どれを選択すべきか Silverlight 4ならばRx一択  Taskないですから  将来VS11/SL5に移行してTask中心になったとしても、 そのままawait出来るので問題はない Silverlight 5ではVS11を見据えて基本的なラップは TaskのFromAsyncで行う  処理自体はContinueWithで組んでもいいけれど、素 のTaskは使いづらいのでRxを使うのがベター  同じく将来的にはRxはawait可能なので大丈夫 WinRTや.NET 4.5 WPFではasync/awaitで  一つの値を返すものはTask+async/awaitがベスト
  31. 31. 非同期ストリーム処理 Reactive Extensions  単体の非同期処理はTaskに譲っても、Rxにはイベン ト処理+それらから流れてくるストリームをそのま ま非同期処理して、非同期ストリーム化させる、な どなど、非同期においても、まだ多くの役割がある TPL Dataflow  .NET 4.5搭載のTaskベースの非同期ストリーム処理ラ イブラリ  Rxと直接対決になるかどうかはまだ分からない
  32. 32. Rx v2 Beta ダウンロードセンター or NuGetのpre releaseから 入手可能  http://www.microsoft.com/download/en/details.aspx?i d=29058 .NET 4.5/SL5/WP 7.1専用 高速化 .NET Portable Library対応  一つのプロジェクトで全てのプラットフォームに対 応可能になる
  33. 33. まとめ C#5.0超素晴らしい Rxの立ち位置は、非同期処理では若干難しくなっ てきている  将来的にはシンプルなケースでは完全不要でしょう  ではRxに価値はないかというとそんなことはなくて、 メインであるイベント処理への活用や非同期スト リーム処理などの方向で使えます  なにより、現時点での唯一の解

×