Hokuriku.NET C#
Rx編
February 11 th /March 17 th , 2012
鈴木孝明
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
ライブラリの入手
• NuGet Gallery - Rx-Main より取得
ライブラリの入手
• ダウンロードサイト より取得
• NuGet が使えない場合
Rxの基本はPush通知!!

オブザーバーパターン
オブザーバーパターンとは
• 疎結合のためのデザインパターン
• 具象クラス間の依存なしに状態変化を通知する
• 例) データ変更 → UI更新
• データがUIを知っている設計は極めて汎用性が低い

• 観測対象 (サブジェクト) と観測者 (オブザーバー) で抽象化
• 一般的にはインターフェース/イベントで実現
オブザーバーパターンの構成
基本インターフェース
• IObserver<T> : 観測者
OnNext(T value)

状態の変更を通知

OnError(Exception error)

エラーの発生を通知

OnCompleted()

完了を通知

• IObservable<T> : 観測対象
Subscribe(IObserver<T> observer)

通知先を登録

• .NET Framework 4で新たに搭載された
• .NET 3.5 SP1 / Silverlight 4環境ではRxライブラリが提供する
• Windows Phone 7には標準搭載
Push型 vs Pull型
Push型

Pull型

• コネクションを張り、受信待機
• IObservable<T>

• 各々必要に応じて取得しに行く
• IEnumerable<T>
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 Cold
Hot 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
Rx入門

Rx入門