過去記事インデックス
- Reactive Extensions再入門 その1
- Reactive Extensions再入門 その2「IObservableインターフェースとIObserverインターフェース」
- Reactive Extensions再入門 その3「IObservableのファクトリメソッド」
- Reactive Extensions再入門 その4「Timer系のファクトリメソッド」
- Reactive Extensions再入門 その5「HotとCold」
- Reactive Extensions再入門 その6「HotなIObservableを作成するファクトリ」
- Reactive Extensions再入門 その7「LINQスタイルの拡張メソッド」
- Reactive Extensions再入門 その8「SkipとTakeメソッド」
- Reactive Extensions再入門 その9「Skip + Take + Repeat = ドラッグ」
- Reactive Extensions再入門 その10「Doメソッド」
- Reactive Extensions再入門 その11「Catchメソッド」
- Reactive Extensions再入門 その12「Finallyメソッドとリソース解放」
- Reactive Extensions再入門 その13「最後の値を取得するLatestとMostRecentメソッド」
- Reactive Extensions再入門 その14「Nextメソッド」
- Reactive Extensions再入門 その15「To*****系メソッド」
- Reactive Extensions再入門 その16「最大、最少、平均を求めるメソッド」
- Reactive Extensions再入門 その17「集計するメソッド」
- Reactive Extensions再入門 その18「CountメソッドとLongCountメソッド」
- Reactive Extensions再入門 その19「AnyメソッドとAllメソッド」
- Reactive Extensions再入門 その20「GroupByメソッドでグルーピングしてみよう」
- Reactive Extensions再入門 その21「GroupByUntilメソッド」
- Reactive Extensions再入門 その22「単一の値を取得するメソッド」
- Reactive Extensions再入門 その23「重複を排除するメソッド」
- Reactive Extensions再入門 その24「単一の値を取得するメソッド その2」
- Reactive Extensions再入門 その25「値をまとめるBufferメソッド」
- Reactive Extensions再入門 その26「値をまとめるWindowメソッド」
- Reactive Extensions再入門 その27「時間でフィルタリング?Sampleメソッド」
- Reactive Extensions再入門 その28「落ち着いたら流すThrottleメソッド」
- Reactive Extensions再入門 その29「値を指定した時間だけ遅延させるDelayメソッド」
はじめに
長いもので30回目です!今回はTimeoutメソッドを紹介したいと思います。
Timeoutメソッド
ここでは、Timeoutメソッドについて説明します。Timeoutメソッドは名前の通りIObservable
public static IObservable<T> Timeout<T>( this IObservable<T> source, TimeSpan dueTime);
dueTimeでタイムアウトの時間を指定します。TimeSpan以外にもDateTimeOffsetでタイムアウトを指定するオーバーロードがありますが、ここでは紹介を割愛します。このメソッドのコード例を下記に示します。
var subscriber = Observable // 0〜4の値をi秒間隔で発行する .Generate(0, i => i < 5, i => i + 1, i => i, i => TimeSpan.FromSeconds(i)) // 3500ms以上間隔があくとタイムアウト .Timeout(TimeSpan.FromMilliseconds(3500)) // 購読 .Subscribe( i => Console.WriteLine("{0:HH:mm:ss} OnNext({1})", DateTime.Now, i), ex => Console.WriteLine("{0:HH:mm:ss} OnError({1})", DateTime.Now, ex), () => Console.WriteLine("{0:HH:mm:ss} OnCompleted()", DateTime.Now)); // Enterを押すと購読終了 Console.ReadLine(); subscriber.Dispose();
このコードでは、Generateメソッドを使って0, 1, 2, 3, 4の値を0s, 1s, 2s, 3s, 4s間隔で発行しています。それに対してTimeoutメソッドで3.5s(3500ms)を指定しています。このコードの実行結果を以下に示します。
12:39:48 OnNext(0) 12:39:49 OnNext(1) 12:39:51 OnNext(2) 12:39:54 OnNext(3) 12:39:58 OnError(System.TimeoutException: 操作がタイムアウトしました。)
最後の4が発行されるのに4秒間が空いてしまうので、TimeoutExceptionが発行されSubscribeのOnErrorに処理がいきます。このように、時間を要する処理のタイムアウトを簡単に指定することが出来ます。
このTimeoutメソッドにはタイムアウト時の動作をカスタマイズすることが出来るオーバーロードがあります。そのメソッドのシグネチャを以下に示します。
public static IObservable<T> Timeout<T>( this IObservable<T> source, TimeSpan dueTime, IObservable<T> other);
第三引数のotherで、タイムアウトが起きたときに代わりに値を発行するIObservable
var subscriber = Observable // 0〜4の値をi秒間隔で発行する .Generate(0, i => i < 5, i => i + 1, i => i, i => TimeSpan.FromSeconds(i)) // 3500ms以上間隔があくとタイムアウト .Timeout( TimeSpan.FromMilliseconds(3500), // タイムアウトの時に流す値を指定 Observable.Create<int>(o => { Console.WriteLine("{0:HH:mm:ss} Error Action", DateTime.Now); // -1を流して完了 o.OnNext(-1); o.OnCompleted(); return Disposable.Empty; })) // 購読 .Subscribe( i => Console.WriteLine("{0:HH:mm:ss} OnNext({1})", DateTime.Now, i), ex => Console.WriteLine("{0:HH:mm:ss} OnError({1})", DateTime.Now, ex), () => Console.WriteLine("{0:HH:mm:ss} OnCompleted()", DateTime.Now)); // Enterを押すと購読終了 Console.ReadLine(); subscriber.Dispose();
TimeoutメソッドでObservable.Createメソッドを使ってタイムアウトの時に-1の値を流してIObservable
13:08:09 OnNext(0) 13:08:10 OnNext(1) 13:08:12 OnNext(2) 13:08:15 OnNext(3) 13:08:19 Error Action 13:08:19 OnNext(-1) 13:08:19 OnCompleted()
最初のコード例ではTimeoutExceptionが発生していましたが、この例ではObservable.Createで作成したIObservableから発行された値が後続に流れていることが確認できます。このようにタイムアウトとタイムアウトに伴って発行する値を差し替えたりすることが出来ます。