かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

Reactive Extensions再入門 その28「落ち着いたら流すThrottleメソッド」

過去記事インデックス

はじめに

今回はThrottleメソッドです!さくっといきましょう。

Throttleメソッド

ここでは、Throttleメソッドについて説明します。Throttleメソッドは指定した間、新たな値が発行されなかったら最後に発行された値を後続に流すメソッドです。メソッドのシグネチャを以下に示します。

public static IObservable<T> Throttle<T>(
    this IObservable<T> source, 
    TimeSpan dueTime);

第二引数のdueTimeで後続に値を流すための判断基準になる間隔を指定します。このメソッドの使用例を下記に示します。

var source = new Subject<int>();
// 500ms値が発行されなかったら最後に発行された値を後続に流す
source
    .Throttle(TimeSpan.FromMilliseconds(500))
    // 渡ってきた値を時間つきで表示
    .Subscribe(i =>
        Console.WriteLine("{0:HH:mm:ss.fff} {1}", DateTime.Now, i));

// 100ms間隔で値を発行
foreach (var i in Enumerable.Range(1, 10))
{
    // 発行した値を出力しておく
    Console.WriteLine("{0:HH:mm:ss.fff} OnNext({1})",DateTime.Now, i);
    source.OnNext(i);
    Thread.Sleep(100);
}

// 2000ms sleep
Console.WriteLine("{0:HH:mm:ss.fff} Sleep(2000)", DateTime.Now);
Thread.Sleep(2000);

// 100ms間隔で値を発行
foreach (var i in Enumerable.Range(1, 5))
{
    // 発行した値を出力しておく
    Console.WriteLine("{0:HH:mm:ss.fff} OnNext({1})", DateTime.Now, i);
    source.OnNext(i);
    Thread.Sleep(100);
}

// 2000ms sleep
Console.WriteLine("{0:HH:mm:ss.FFF} Sleep(2000)", DateTime.Now);
Thread.Sleep(2000);

Throttleメソッドで500msの間、値が発行されなかった場合に後続に値を流すようにしています。そのあと、foreachで値を10個100ms間隔で発行して2000msスリープしています。次に、値を5個100ms間隔で発行して、2000msスリープしています。実行結果を以下に示します。

23:05:36.003 OnNext(1)
23:05:36.116 OnNext(2)
23:05:36.217 OnNext(3)
23:05:36.317 OnNext(4)
23:05:36.417 OnNext(5)
23:05:36.517 OnNext(6)
23:05:36.617 OnNext(7)
23:05:36.717 OnNext(8)
23:05:36.817 OnNext(9)
23:05:36.917 OnNext(10)
23:05:37.023 Sleep(2000)
23:05:37.420 10           <- ここ
23:05:39.026 OnNext(1)
23:05:39.126 OnNext(2)
23:05:39.226 OnNext(3)
23:05:39.326 OnNext(4)
23:05:39.426 OnNext(5)
23:05:39.526 Sleep(2000)
23:05:39.926 5           <- ここ

実行結果で「<- ここ」で示している箇所が、Subscribeで出力している箇所です。直前のOnNextから500ms後に出力されていることが確認できます。
このThrottleメソッドは、TextBoxの入力が終わって1秒後に自動で検索処理が実行されるケースなどで使います。