かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

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秒後に自動で検索処理が実行されるケースなどで使います。