Advertisement

実践 Reactive Extensions

Sep. 1, 2011
Advertisement

More Related Content

Advertisement

Recently uploaded(20)

Advertisement

実践 Reactive Extensions

  1. 実践 Reactive Extensions 2011/08/27 Silverlight/Phone Quest I 伊勢 シン (Microsoft MVP for Windows Phone)
  2. 自己紹介 • 伊勢 シン – Microsoft MVP for Windows Phone (Oct 2010-Sep 2011) • 大阪で働くスマートフォンプログラマ – 目指すは「スマートフォンの万屋」 – iOSアプリをビルドをしながらAndroidアプリのコーディングやったりとか – Windows Phone 7 も少々 • 趣味もスマートフォンアプリ開発で – EbIRC – SongTweeter • コミュニティ – スマートフォン勉強会 代表 – Windows Phone Arch 関西スタッフ?
  3. おしながき • Reactive Extension について – 基本的なこと – 書き方の考え方 • 実例でみるReactive Extensions – RSSの取得 – ログインが必要なページの先からファイルダウンロード – 複数ページをダウンロードして一括処理 – なんでもいいからとにかく非同期
  4. Reactive Extensions について
  5. そもそもReactive Extensionsって何ぞ • Reactive Extensions (Rx) • LINQの機能を時間軸に拡張するライブラリ – LINQ to SQL, LINQ to Objects に対する LINQ to Events, LINQ to Asynchronous – “WhereでフィルタしてSelectで射影できるならLINQ といえる” – by @neuecc
  6. なにがうれしいの? • 複雑な非同期処理を「直線的に」書ける – 非同期のコードはひたすらネストがつづく – “もはやカオスすぎて頭が痛い” by @neuecc • 例外処理をひとまとめに書ける – Subscribeの第2引数のラムダで一括処理可能 • その他各種特典 – 中断処理も簡単。 – リトライ処理 – 処理の待ち合わせ、結合など
  7. “もはやカオスすぎて頭が痛い” 例
  8. そう、Rxならね WebRequest.Create("http://hoge") .GetResponseAsObservable() .Select(res => new StreamReader(res.GetResponseStream()).ReadToEnd()) .SelectMany(s => WebRequest.Create(s).GetResponseAsObservable()) .Select(res => new StreamReader(res.GetResponseStream()).ReadToEnd()) .ObserveOnDispatcher() .Subscribe( s => MessageBox.Show(s), e => MessageBox.Show(e.ToString()));
  9. どこでつかえるの? • Windows Phone のクラスライブラリに 標準搭載され、非同期処理しか存在しない Silverlight の存在も相まって注目度アップ • WP7だけでなく、いろいろなところでつかえます – .NET Framework 3.5 / 4 Client Profile – Silverlight 3 / 4 / for Windows Phone – XNA 3.1(Zune) / 4 (Xbox360) – http://www.microsoft.com/download/en/details .aspx?id=24940
  10. どうやって使うの?@WP7 • 以下のアセンブリを参照 – Microsoft.Phone.Reactive – System.Observable • Rxを使いたいcsファイルのusingに以下を追加 – Microsoft.Phone.Reactive • すべてのはじまりは Observable クラス
  11. そもそもマルチスレッドの基本的な考え方 UIスレッド トリガー UI反映 スレッド同期 どこか別のスレッド 時間のかかる処理 結果の処理
  12. Rx コードの基本構成 1.トリガー Observable.FromAsyncPattern<WebResponse>( req.BeginGetResponse, req.EndGetResponse)() .Select(res => XDocument.Load(res.GetResponseStream())) .SelectMany(doc => doc.Element("Categories").Elements("Category")) .Select(elem => new { ID = elem.Element("ID").Value, 2.データ処理 Name = elem.Element("Name").Value }) .ObserveOnDispatcher() 3.スレッド同期 .Subscribe(res => { // UI反映 }, err => { // 例外処理 4.UI反映 });
  13. 簡単にRxを書くために • 通信処理系のRxを書くなら RxAsynchronousHelper を使うと便利です。 – 通信を非同期に行うためのRxのおきまり処理を うまくパッケージングしたクラス。あるだけで便利。 – by @neuecc – http://neue.cc/2010/11/26_286.html
  14. 実例で見る Reactive Extensionsの使い方
  15. RSSを受信する • 単純な処理の例 – XDocumentの名前空間つけないといけないのだけ なんとかならんかと思っています。
  16. 単純なRSS受信 private const string Name_RDF = "{http://www.w3.org/1999/02/22-rdf-syntax-ns#}RDF"; private const string Name_Item = "{http://purl.org/rss/1.0/}item"; private const string Name_Title = "{http://purl.org/rss/1.0/}title"; private const string Name_Link = "{http://purl.org/rss/1.0/}link"; var req = WebRequest.CreateHttp("http://d.hatena.ne.jp/iseebi/rss"); Observable.FromAsyncPattern<WebResponse>(req.BeginGetResponse, req.EndGetResponse)() .Select(res => XDocument.Load(res.GetResponseStream())) .Select(doc => from elem in doc.Element(Name_RDF).Elements(Name_Item) select new { Title = elem.Element(Name_Title).Value, Link = elem.Element(Name_Link).Value }) .ObserveOnDispatcher() .Subscribe(res => { foreach (var item in res) { Debug.WriteLine("{0} -> {1}", item.Title, item.Link); } });
  17. RxAsynchronousHelperを使った場合 WebRequest.CreateHttp("http://d.hatena.ne.jp/iseebi/rss") .GetResponseAsObservable() .Select(res => XDocument.Load(res.GetResponseStream())) .Select(doc => from elem in doc.Element(Name_RDF).Elements(Name_Item) select new { Title = elem.Element(Name_Title).Value, Link = elem.Element(Name_Link).Value }) .ObserveOnDispatcher() .Subscribe(res => { foreach (var item in res) { Debug.WriteLine("{0} -> {1}", item.Title, item.Link); } });
  18. ダウンロードの結果解析で次のファイルへ • ログインが必要なページなどに有効 • SelectManyにすれば、流れに全く関係のない IObservable<T> を新規にメソッドチェーンに 流せる。
  19. テキストに書いてあるURLをさらに取得 // URLが書いてある WebRequest.CreateHttp("http://iseebi.half-done.net/test/url.txt") .DownloadStringAsync() // 新しいIObservableを流す .SelectMany(res => WebRequest.CreateHttp(res).DownloadStringAsync()) .ObserveOnDispatcher() .Subscribe(res => { Debug.WriteLine(res); });
  20. 一括ダウンロードしてから処理 • 複数のファイルをダウンロードし、 ダウンロード完了後に処理したい場合 – 定義ファイルの一括取得など
  21. 一括ダウンロード // ダウンロード処理を一括でリストにする var l = new List<IObservable<string>>() { WebRequest.CreateHttp("http://iseebi.half-done.net/test/phone.txt").DownloadStringAsync(), WebRequest.CreateHttp("http://iseebi.half-done.net/test/clientappdev.txt").DownloadStringAsync(), WebRequest.CreateHttp("http://iseebi.half-done.net/test/deviceappdev.txt").DownloadStringAsync(), WebRequest.CreateHttp("http://iseebi.half-done.net/test/powershell.txt").DownloadStringAsync(), }; // ForkJoinで一括処理 Observable.ForkJoin(l) .ObserveOnDispatcher() .Subscribe(res => { foreach (var item in res) { Debug.WriteLine(item); } });
  22. なんでもいいからとにかく非同期に • とにかくなんでもいいので非同期にしたい場合、 以下の組み合わせで何もないところから処理を 作り出せる。 – Observable.Defer – Observable.ToAsync Observable.Defer(Observable.ToAsync(() => System.Threading.Thread.Sleep(3000))) .ObserveOnDispatcher() .Subscribe(res => Debug.WriteLine("Success!!!"));
  23. まとめ • Rx 使うと非同期処理が きれい、かんたん、便利に書けます。 – いくつかの実例をみてご紹介しました。 • Special thanks to @neuecc
Advertisement