Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Reactive Extensionsで WP7の非同期処理を簡単に
Search
Yoshifumi Kawai
May 21, 2011
Technology
76
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Reactive Extensionsで WP7の非同期処理を簡単に
Yoshifumi Kawai
May 21, 2011
More Decks by Yoshifumi Kawai
See All by Yoshifumi Kawai
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
5
5.2k
.NET for Android with Native AOT Built with Cursor
neuecc
0
8k
CysharpのOSS群から見るModern C#の現在地
neuecc
2
48k
R3のコードから見る実践LINQ実装最適化・コンカレントプログラミング実例
neuecc
5
57k
.NETの非同期戦略とUnityとの相互運用
neuecc
3
56k
他言語がメインの場合のRustの活用法 - csbindgenによるC# x Rust FFI実践事例
neuecc
7
42k
Modern High Performance C# 2023 Edition
neuecc
4
16k
CEDEC 2023 モダンハイパフォーマンスC# 2023 Edition
neuecc
9
120k
C#11 による世界最速バイナリシリアライザー「MemoryPack」の作り方
neuecc
1
43k
Other Decks in Technology
See All in Technology
実践! SRE × AI - ABEMA における AIOps -
tetsuya28
8
3.1k
CTO Night|NotionのAIエージェントとFDE
kzkhykw1991
0
230
LambdaWebFunctionsを試してみた / exploring-lambda-web-functions
koukihosaka
1
360
しろおびから始める!ログ活用の第一歩
shumei_ito
0
960
hackers_champloo_2026_tidb
makocchi
0
170
Local CI × GitHub Actions
gogutan
3
230
実体験から学ぶ分析エージェントの開発と運⽤
recruitengineers
PRO
8
2.4k
NDIでApple Vision Proにリアルタイム映像送信
jyouryuusui
0
130
TinyGoでオブザーバビリティ?OpenTelemetryはTinyGoで使えるのか / Is OpenTelemetry available in TinyGo environment?
ymotongpoo
2
140
QA4AI 2026-Oct 生成AI時代の品質保証
tokuty
1
890
Kiro Crewをはじめよう
kizawa2020
1
160
JAWS-UGグッズ職人仕事の流儀
kentapapa
0
120
Featured
See All Featured
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.8k
30 Presentation Tips
portentint
PRO
1
430
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.8k
Site-Speed That Sticks
csswizardry
13
1.6k
Deep Space Network (abreviated)
tonyrice
0
370
Raft: Consensus for Rubyists
vanstee
142
7.8k
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
400
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
35
2.9k
Fireside Chat
paigeccino
43
4.1k
Designing for Timeless Needs
cassininazir
1
530
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
280
Between Models and Reality
mayunak
4
500
Transcript
Reactive Extensionsで WP7の非同期処理を簡単に @neuecc – 2011/5/21
Twitter => @neuecc Blog => http://neue.cc/ HNはneuecc
読むときは“のいえ”と読ませてます ⚫ ドメイン繋いだだけなので発音するの考えてなかっ た(のでccは抜きで←発音しにくいですから) Microsoft MVP for Visual C#(2011/4-) WP7で作った物 ⚫ ReactiveOAuth, Utakotoha WP7の好きなtheme ⚫ light + lime Profile
LINQの概要/LINQとしてのReactive Extensions 非同期処理の面倒さと如何にRxが癒すか .NETにおける非同期パターンの説明 Rxの基本(購読, キャンセル,
例外処理) 非同期処理で使うRxのメソッド概略 作った物紹介 Agenda
Linq to Introduction
// クエリ構文 var query = from x in source where
x % 2 == 0 select x * x; // メソッド構文 var query = source .Where(x => x % 2 == 0) .Select(x => x * x); Language INtegrated Query
データソースを統一的な書法で処理できる WhereでフィルタしてSelectで射影できるならそれ はLINQって言えます! SQL関係ないし、C#も飛び越えて生きる概念 JavaScript移植もあるしね ⚫
linq.js – http://linqjs.codeplex.com/ ⚫ RxJS(Reactive Extensions for JavaScript) LINQって何?
Reactive Extensions LINQのデータソースとは to Objects 配列 List<T> Stream 無限リスト to
Xml XML (JSON) to Sql Database to Events TextChanged ジェスチャー センサー MusicPlayer to Asynchronous IO – WebRequest Timer – ポーリング Thread – 長時間かかる処理
Reactive Extensions = Linq to Events Linq to Asynchronous LINQにおけるデータソースの拡張
……というだけじゃない 時間という軸を中心にした基盤
Rxの基本軸は時間 IE<T> length IO<T> time event async IE<T> => IE<T>も乗っかることで「全てのデータソース」が合成可能に!
Async Programming Blues
var req = WebRequest.Create("http://hoge/"); var res = req.GetResponse(); var str
= new StreamReader(res.GetResponseStream()).ReadToEnd(); 簡単。でも、Silverlight/WP7には同期APIは無い。 ⚫ UIがブロックされるのダメ絶対 Thread立ててそっちで実行させれば? ⚫ まあそうです ⚫ でもないものはないのでしょうがない ⚫ そのかわり特に気を使わなくても必ずUIノンブロッ キングになる(※但しCPUヘヴィな処理は除く) 古き良き同期コード
var req = WebRequest.Create("http://hoge"); req.BeginGetResponse(ar => { var res =
req.EndGetResponse(ar); var str = new StreamReader(res.GetResponseStream()) .ReadToEnd(); Dispatcher.BeginInvoke(() => MessageBox.Show(str)); }, null); 非同期はBeginHoge -> EndHoge 基本、クロージャ全開で書く 面倒くさいけれど、まあこれぐらいなら? しょうがないので非同期で書く
var req = WebRequest.Create("http://hoge"); req.BeginGetResponse(ar => { var res =
req.EndGetResponse(ar); var url = new StreamReader(res.GetResponseStream()) .ReadToEnd(); var req2 = WebRequest.Create(url); req2.BeginGetResponse(ar2 => { var res2 = req2.EndGetResponse(ar2); var str = new StreamReader(res2.GetResponseStream()) .ReadToEnd(); Dispatcher.BeginInvoke(() => MessageBox.Show(str)); }, null); }, null); ネストするとかなりヤバい
WP7ではネットワーク周りのコードでは100%例外 発生の可能性がある 圏外だったり通信が超低速だったりすると? ⚫ Hello, Timeout. ⚫ 山崎春のWebException祭り
⚫ 何の手立てもしないとアプリ落ちるよ 予期される例外だし、固有の後処理もあるだろう し、復帰可能にすべきなので、その場その場で catchして始末するのが無難 通信箇所に例外処理は必須
var req = WebRequest.Create("http://hoge"); req.BeginGetResponse(ar => { try { var
res = req.EndGetResponse(ar); var url = new StreamReader(res.GetResponseStream()).ReadToEnd(); var req2 = WebRequest.Create(url); req2.BeginGetResponse(ar2 => { var res2 = req2.EndGetResponse(ar2); var str = new StreamReader(res2.GetResponseStream()).ReadToEnd(); Dispatcher.BeginInvoke(() => textBlock1.Text = str); }, null); } catch(WebException e) { Dispatcher.BeginInvoke(() => MessageBox.Show(e.ToString())); } }, null); 内側なのは見た目だけ 非同期中に起こる例外はEnd時に戻される ここの例外をcatchしてない catchできるのは同じ関数のブロック内だけ
var req = WebRequest.Create("http://hoge"); req.BeginGetResponse(ar => { try { var
res = req.EndGetResponse(ar); var url = new StreamReader(res.GetResponseStream()).ReadToEnd(); var req2 = WebRequest.Create(url); req2.BeginGetResponse(ar2 => { try { var res2 = req2.EndGetResponse(ar2); var str = new StreamReader(res2.GetResponseStream()).ReadToEnd(); Dispatcher.BeginInvoke(() => MessageBox.Show(str)); } catch (WebException e) { Dispatcher.BeginInvoke(() => MessageBox.Show(e.ToString())); } }, null); } catch (WebException e) { Dispatcher.BeginInvoke(() => MessageBox.Show(e.ToString())); } }, null); もはやカオスすぎて頭痛い
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())); Reactive Extensionsを使うと 内部で発生する例外は全てここで扱える ネストが消滅し完全フラット 拡張メソッド(後で説明します)
ネストがなくなって平らに 統一的な例外処理が可能 + その他の機能もいっぱい ⚫ リトライ処理 ⚫
イベントやシーケンスとの合成など Rxを使うことの利点
Asynchronous Patterns
非同期パターンは概ね二つ ⚫ APM(Asynchronous Programming Model) ⚫ BeginXxx-EndXxx ⚫ WebRequest.BeginGetResponseとか
⚫ EAP(Event-based Asynchronous Pattern) ⚫ XxxAsync-XxxCompleted ⚫ WebClient.DownloadStringAsync/Copletedとか 将来的には? ⚫ Rx(WP7では標準搭載ですが.NET4ではまだ) ⚫ Task(.NET4では標準搭載ですがWP7ではまだ) ⚫ C# 5.0 Async(まだCTP, 恐らく2年ぐらい先) 非同期のもと
Rxで使うならAPMのほうが相性良い APMは上から下まで流れてるが、EAPは最後に発火 させなければならない これはネストする場合に致命的に面倒 // APM WebRequest.Create("http://hoge")
.GetResponseAsObservable() .Subscribe(); // EAP var wc = new WebClient(); wc.DownloadStringCompletedAsObservable() .Subscribe(); wc.DownloadStringAsync("http://hoge"); どっちがいいの? Subscribe後に発火
APM, WebRequest->WebResponseはプリミティブ すぎて、一々Stream扱ったり面倒くさい WebClientのDownloadString的なのが欲しい なら拡張メソッドで自作すれば解決 FromEventやFromAsyncPatternは定型句なので、こ
ちらも拡張メソッドで隔離するのがお薦め 拡張メソッドのすゝめ
public static IObservable<IEvent<DownloadStringCompletedEventArgs>> DownloadStringCompletedAsObservable(this WebClient webClient) { return Observable.FromEvent< DownloadStringCompletedEventHandler,
DownloadStringCompletedEventArgs>( h => h.Invoke, // おまじない h => webClient.DownloadStringCompleted += h, h => webClient.DownloadStringCompleted -= h); } FromEvent(FromEventPattern) 戻り値はIEvent<EventArgs>のIO<T> FromEvent<EventHandler,EventArgs>
FromAsyncPatternの戻り値はデリゲート ⚫ つまり自分でInvokeするまで実行されない 拡張メソッドにするなら即実行のほうが便利? Task.Factory.StartNew的なイメージで public static
IObservable<WebResponse> GetResponseAsObservable(this WebRequest request) { return Observable.FromAsyncPattern<WebResponse>( request.BeginGetResponse, request.EndGetResponse) .Invoke(); } FromAsyncPattern
Stringが戻ったほうが便利ですよね POSTなども同じように作っておくと楽になる public static IObservable<string> DownloadStringAsync(this WebRequest request)
{ return request.GetResponseAsObservable() .Select(res => { using (var stream = res.GetResponseStream()) using (var sr = new StreamReader(stream)) { return sr.ReadToEnd(); } }); } DownloadStringAsync(の自作)
Rxが提供してくれているのは基本的な道具 Rxは「分離しやすい」のも特徴的なメリット <T>への拡張メソッドや、IO<T>->IO<T>の拡張メ ソッドなどを作って、すっきりさせよう WebRequest.Create("http://hoge") .DownloadStringAsync() .SelectMany(s
=> WebRequest.Create(s).DownloadStringAsync()) .ObserveOnDispatcher() .Subscribe( s => MessageBox.Show(s), e => MessageBox.Show(e.ToString())); 最初の例もこんなにスッキリ
Basics of Rx
Microsoft.Phone.Reactiveを参照する System.Observableを参照する ⚫ WP7には標準搭載 ⚫ NET4版は別途インストールしてSystem.Reactiveを 定形的な流れは
FromEvent/FromAsyncして(IO<T>の生成) SelectなりWhereなりLINQでデータを加工して ObserveOnDispatcherして(値をUIスレッドに戻す) Subscribeする 書き方の基本
// Subscribeの戻り値はIDisposableなので、Disposeすればおk var disposable = AsyncMethod().Subscribe(); disposable.Dispose(); // イベントの場合はデタッチになるよ var
buttonClick = button.ClickAsObservable().Subscribe(); buttonClick.Dispose(); // Listに入れてまとめてDisposeとか var disposables = new List<IDisposable>(); disposable.Add(button.ClickAsObservable().Subscribe()); disposable.Add(button.ClickAsObservable().Subscribe()); disposable.ForEach(d => d.Dispose()); // IList<IDisposable>はCompositeDisposableというのもある var disposables = new CompositeDisposable(); disposable.Dispose(); ところでキャンセルしたい
何も書かない ⚫ 例外はcatchせずスローされてくる SubscribeのonErrorに書く ⚫ Rxのチェーンで発生した例外を全てcatchする ⚫ ここに空のものを書けば例外無視が成立とかも
⚫ ※Tips:一部メソッドが間に挟まれていると(Publishなど) 場合によってはcatchされなくなることも(Publishは内部 で自前でSubscribeしているためチェーンが途切れてる) Catchメソッドを使う ⚫ 例外の型を指定した通常のtry-catchに近いもの ⚫ 戻り値にEmptyを返せば終了、何か別の値を返せばそ れを代替として流すということになる 例外処理は?
// 何も書かないので例外がスローされてくる WebRequest.Create("http://hoge") .DownloadStringAsync() .Subscribe(Debug.WriteLine); // SubscribeのonErrorで全てcatch WebRequest.Create("http://hoge") .DownloadStringAsync() .Subscribe(Debug.WriteLine,
e => { }); // CatchでWebExceptionだけcatch WebRequest.Create("http://hoge") .DownloadStringAsync() .Catch((WebException e) => Observable.Empty<string>()) .Subscribe(Debug.WriteLine); 基本的なのはこの3つ
Compose Patterns
AsyncA AsyncB SelectMany - 直列の結合 AsyncA Zip - 並列の結合 AsyncB
Result
AsyncA AsyncB AsyncC Result AsyncA().SelectMany(a => AsyncB(a)) .Zip(AsyncC(), (b, c)
=> new { b, c }); SelectMany + Zip - 合成の例
AsyncA AsyncC AsyncD Result Observable.ForkJoin(AsyncA(), AsyncB(), AsyncC(), AsyncD()) .Select(xs =>
new { a=xs[0], b=xs[1], c=xs[2], d=xs[3] }); ForkJoin - 並列同時実行 AsyncB
var asyncQuery = from a in AsyncA() from b in
AsyncB(a) from c in AsyncC(a, b) select new { a, b, c }; 多重from(SelectMany) AsyncA AsyncB AsyncC Result
Conclusion
FromEvent/Asyncは拡張メソッドで隔離 ついでにReadToEndなんかも隔離 とりあえずSubscribeの前にObserveOnDispatcher onErrorとCatchで例外をコントロール 色々な合成メソッドで流れをコントロール
もう非同期なんて怖くない! Rxで書くと実は同期で書くよりも柔軟 むしろもう同期でなんて書きたくない! まとめ
Real World Rx
http://reactiveoauth.codeplex.com/ TwitterとかのOAuth認証/通信用ライブラリ 以下のWP7アプリで使われています! ⚫ SongTweeter @iseebi ⚫
NumberPush @mitsuba_tan ⚫ Utakata TextPad @kaorun ⚫ HirganaTwit @hatsune_ ReactiveOAuth
Twitterクライアントを作るわけではないけれど、 ステータスだけTwitterに投稿したい、などはよく あること(特に最近は何でもTwitterだし) new OAuthClient(ConsumerKey, ConsumerSecret, accessToken) { MethodType
= MethodType.Post, Url = "http://api.twitter.com/1/statuses/update.xml", Parameters = { { "status", "ここに投稿する文章" } } } .GetResponseText() // 投稿して、戻り値を得る .Select(XElement.Parse) // xmlの場合はパースしたいよね .Subscribe(); // なにか処理するなり例外処理入れるなり どんな時に使えるの?
WP7だけじゃなく.NET4/SL4向けもあり コードの99%をWP7と共有している ⚫ 残り1%は最近の更新で.NET版Rxが一部WP7版と互換 なくなったため Rxをベースに置くと、コードの可搬性が圧倒的に 高まる
機能面でもRxにタダ乗り出来るので(エラー・リト ライ・タイムアウトなど全部Rxにおまかせ) ライブラリ本体はシンプルなコードのままで強力 な機能を持てる ポータビリティ
http://utakotoha.codeplex.com/ 再生中の曲に応じて日本語歌詞を表示する マーケットプレイスで公開中(Free) ソースコードも公開中 Utakotoha
コードは無理やり全部Rxで割と実験的 GUI周りは強引でボロボロで酷い イベント周りなどは面白く仕上がったかも Modelを別に立てた.NET4クラスライブラリにリン クで参照することによりMSTestでユニットテスト
Molesというモックライブラリを使ってWP7のイベ ント自体を乗っ取り(音楽再生の情報をテストのた めに任意に生成したり) 上手くいってるかはノーコメント コードの中身
Deep Dive Rx
Data Developer Center - Rx http://msdn.microsoft.com/en-us/data/gg577609 二つのドキュメントが出ています
⚫ Hands-on-Lab ⚫ チュートリアル式で触りながら分かりやすく ⚫ まず見て欲しい ⚫ Design Guidelines ⚫ マニュアルみたいなもの ⚫ 更に深くへ 公式見るのがいいよやっぱり
ねぇよんなもん うちのサイトでも見てください:) ⚫ http://neue.cc/ ⚫ http://neue.cc/category/rx 日本語情報は?