Rx入門
-
Upload
takaaki-suzuki -
Category
Technology
-
view
10.644 -
download
0
description
Transcript of Rx入門
February 11th/March 17th, 2012鈴木孝明
Hokuriku.NET C#Rx編
Agenda
• Rxの概要
• オブザーバーパターン
• LINQによる記述
• 時間/イベント/非同期のシーケンス化
• HotとCold
• スケジューラの利用
• 今日のまとめ
さぁ、Rxの世界へ!!
Rxの概要
Rx (Reactive Extensions)とは
• 値群を時間軸に乗ったシーケンスとして捉える
• 時間/イベント/非同期処理をLINQで記述
• .NET 3.5 SP1以降、SL 4以降、WP7で利用可能• 特に非同期APIしかないSilverlight環境で威力を発揮
• Windows Phone 7にのみ標準搭載
• RxJSというJavaScript版もある
• Microsoftの正式なプロジェクト
時間軸を基にしたシーケンス
• IObservable<T>は時間軸に乗る非同期な値群• これに乗せられるものはすべて統一的に扱える
• 例) タイマー/イベント/非同期処理
[出典] 連載 : Reactive Extensions (Rx) 入門 - @IT
時間軸シーケンスのイメージ
• ベルトコンベアのようなイメージで考える• モノが流れてくる (= IObservable<T>からの発行)
• 不純物を取り除く検査が行われる (= Where)
• 梱包作業が行われる (= Select)
• 配送される (= Subscribe)
Where Select
Rxの基本はPush通知!!
オブザーバーパターン
オブザーバーパターンとは
• 疎結合のためのデザインパターン
• 具象クラス間の依存なしに状態変化を通知する• 例) データ変更→ UI更新
• データがUIを知っている設計は極めて汎用性が低い
• 観測対象 (サブジェクト)と観測者 (オブザーバー)で抽象化
• 一般的にはインターフェース/イベントで実現
オブザーバーパターンの構成
基本インターフェース
• IObserver<T> : 観測者
• IObservable<T> : 観測対象
• .NET Framework 4で新たに搭載された• .NET 3.5 SP1 / Silverlight 4環境ではRxライブラリが提供する
• Windows Phone 7には標準搭載
OnNext(T value) 状態の変更を通知
OnError(Exception error) エラーの発生を通知
OnCompleted() 完了を通知
Subscribe(IObserver<T> observer) 通知先を登録
Push型 vs Pull型
• コネクションを張り、受信待機
• IObservable<T>
• 各々必要に応じて取得しに行く
• IEnumerable<T>
Push型 Pull型
IObserver<T>の省略
• IObserver<T>を毎回実装するのは手間• デリゲートを渡すことでオブザーバーの生成を隠蔽
• 隠蔽化によってコードの見え方が変わる• 「IObserver<T>の登録」から「Subscribeで処理」へ
拡張メソッド
一人二役なSubject<T>
• IObservable<T>とIObserver<T>の両方を実装
• Rxにおけるイベント
• いくつかの亜種がある
Subject<T> 最も基本的なもの
BehaviorSubject<T> 初期値ありSubject<T>
ReplaySubject<T> 再発行時にリプレイ
AsyncSubject<T> 非同期処理を模倣
IObservable<T>の生成メソッド
• Observable静的クラスに数多く提供されている• IObservable<T>を毎回実装するのは手間
• 定型句なものは生成メソッドを使って楽をする
Observable.Range(3, 5);3から始まり1ずつインクリメントされた5つの値を返す
Observable.Repeat(1, 3); 1を3回発行
Observable.Create(observer =>{
observer.OnNext(100);observer.OnCompleted();return () => { … }; // Disposer
};
Subscribeで接続されたオブ
ザーバーに対して直接値を発行
宣言的に書ける美しさ!!
LINQによる記述
LINQスタイルでの記述
• メソッド形式
• クエリ式形式
Where/Selectの内部実装
• IObserver<T>で受ける
• フィルタリング/射影
• IObservable<T>で返却
Source.Where(…).Subscribe(observer);
時間軸上の値を統一的に扱おう!!
時間/イベント/非同期のシーケンス化
イベントのシーケンス化
• EventHandler/EventHandler<T>形式から生成• Observable.FromEventPatternメソッドを利用
• イベント通知はEventPattern<T>型 (Sender & EventArgs)で行われる
• リフレクションによるオーバーロードもある
• Action<T>/Func<T>など、独自形式から生成• Observable.FromEventメソッドを利用
• 通知する型の形式変換も可能で、非常に柔軟性が高い
非同期処理のシーケンス化
• ToAsync/Startメソッドでデリゲートからの生成• 引数を与えたり、戻り値を受けることも可能
• BeginXxx/EndXxx (APMパターン)からの生成• FromAsyncPatternメソッドを利用
• OnCompletedが呼ばれるまでが非同期処理中• 非同期処理の結果はOnCompletedの直前にOnNextで通知される
• 結果が何もない場合はUnit構造体 (voidの代替) が通知される
• 実行スレッドは既定でThreadPool上• GUIアプリの場合、このままではUIに触れないので注意
IObservable<T>の性質を知ろう!!
HotとCold
Hot vs ColdHot Observable Cold Observable
• すべてのIObserver<T>に対して一度に同じ値を送信
• それぞれのIObserver<T>に対して個別に値を送信
Cold to Hot 変換
• 一時的に流れを堰き止める (IConnecableObservable<T>)
• その間に支流を作り、完成したら再放流
Rxの柔軟性はココにあり!!
スケジューラの利用
スケジューラの概要
• 処理をいつ/どこで実行するかを振り分ける
• IObservable<T>の生成メソッドに設定して利用• 基本的にはメソッドのオーバーロードで指定可能
• 指定しないメソッドは暗黙にデフォルトが設定される
• スレッド切り替え• Observable.ObserveOnメソッドで以降の動作スレッドを変更
• 柔軟性が確保される反面、パフォーマンスが悪い• Observable.RangeはEnumerable.Rangeより数百倍遅い
スケジューラの種類
CurrentThreadScheduler 現在実行中のスレッド上で、キューに登録されたものから順に処理
ImmediateScheduler 現在実行中のスレッド上で、即座に実行
NewThreadScheduler それぞれ別スレッドで処理
EventLoopScheduler 指定されたスレッド上で処理
ThreadPoolScheduler スレッドプール上で処理
TaskPoolScheduler 指定されたTaskFactory上で処理
SynchronizationContextScheduler指定されたSynchronizationContextに同期して処理
ControlScheduler指定されたWinFormsコントロールのあるメッセージループで処理
DispatcherScheduler 指定されたDispatcher上で処理
ココだけは押さえよう!!
今日のまとめ
まとめ
• オブザーバーパターンによるPush通知が基本
• 値群を時間軸に乗ったシーケンスとして捉える
• IObservable<T>とIObserver<T>で実現される
• 時間/イベント/非同期処理をLINQで記述可能• メソッド形式/クエリ式形式どちらでも書ける
• メソッド形式の方ができることは多い
まとめ
• HotとColdという性質の違いがある• Hot : すべてのIObserver<T>に対して一度に同じ値を送信
• Cold : それぞれのIObserver<T>に対して個別に値を送信
• スケジューラで柔軟性を提供している• スレッドの切り替え
• 処理順序の変更
• パフォーマンスは大幅に低下する
• .NET 3.5 SP1以降、SL 4以降、WP7で利用可能
参考記事
• 連載 : Reactive Extensions (Rx) 入門
• Reactive Extensions入門「まとめ」
• Reactive Extensions再入門
• Rx入門 -インデックス
• neue.cc