ThrottleLast
1. 概要
ThrottleLast は、ソースシーケンスを一定期間ごとにサンプリングし、各期間中に受け取った最後の値を下流に発行するオペレーターです。
定期的な UI 更新やセンサーデータのサンプリングなど、一定間隔で最新の値を取得したい場合に適しています。
サンプリングのタイミングは overload によって異なります。TimeSpan 版は最初の値を受け取ってから一定時間後、sampler 版は外部 Observable が値を発行した時点、非同期関数版は sampler の ValueTask が完了した時点で、その期間中の最後の値を発行します。
2. シグネチャ
TimeSpan によるサンプリング
public static Observable<T> ThrottleLast<T>(
this Observable<T> source,
TimeSpan timeSpan)public static Observable<T> ThrottleLast<T>(
this Observable<T> source,
TimeSpan timeSpan,
TimeProvider timeProvider)最初の値を受け取ると timeSpan のタイマーを開始し、タイマーが発火した時点で、その間に受け取った最後の値を発行します。発行後、次の値を受け取ると新しいタイマーが開始されます。
source.ThrottleLast(TimeSpan.FromSeconds(1))この例では、最初の値を受け取るとタイマーが開始され、その期間中に受け取った最後の値が下流に発行されます。区間内に値がなかった場合は何も発行されません。
サンプラー Observable によるサンプリング
public static Observable<T> ThrottleLast<T, TSample>(
this Observable<T> source,
Observable<TSample> sampler)sampler が値を発行するたびに、その時点でソースから最後に受け取った値を発行します。
source.ThrottleLast(Observable.Interval(TimeSpan.FromSeconds(1)))この例では、sampler が値を発行したタイミングで、その時点までにソースから受け取っている最後の値を発行します。前回のサンプリング以降にソース値がない場合は何も発行されません。
非同期関数によるサンプリング
public static Observable<T> ThrottleLast<T>(
this Observable<T> source,
Func<T, CancellationToken, ValueTask> sampler,
bool configureAwait = true)最初の値が届くと sampler 非同期関数を開始し、関数が完了した時点でその間に受け取った最後の値を発行します。
source.ThrottleLast(async (value, ct) =>
{
await Task.Delay(TimeSpan.FromMilliseconds(500), ct);
})この例では、最初の値を受け取ると非同期 sampler が開始され、完了時点でその間に受け取った最後の値を発行します。発行後、次の値を受け取ると新しい非同期サンプリング期間が始まります。
overload の使い分け
| overload | 使う場面 |
|---|---|
TimeSpan | 固定間隔のサンプリングで十分な場合(最も一般的) |
TimeSpan, TimeProvider | ユニットテストで時間を制御したい場合 |
Observable<TSample> | 外部イベントでサンプリングタイミングを制御したい場合 |
Func<T, CancellationToken, ValueTask> | 値に応じてサンプリング間隔を動的に変えたい場合 |
3. サンプルコード
using R3;
// 1 秒ごとにセンサーの最新値を取得
sensorDataObservable
.ThrottleLast(TimeSpan.FromSeconds(1))
.Subscribe(value => UpdateDisplay(value));
// マウスの位置を 100ms ごとにサンプリング
mousePositionObservable
.ThrottleLast(TimeSpan.FromMilliseconds(100))
.Subscribe(pos => Console.WriteLine($"位置: ({pos.X}, {pos.Y})"));
// サンプラー Observable を使ったサンプリング
var tick = Observable.Interval(TimeSpan.FromSeconds(2));
source
.ThrottleLast(tick)
.Subscribe(x => Console.WriteLine($"サンプル: {x}"));4. 補足
ThrottleFirst / Debounce との違い
| オペレーター | 発行する値 | 発行タイミング |
|---|---|---|
| ThrottleFirst | 最初の値 | 値が来た直後 |
| ThrottleLast | 最後の値 | 期間の終了時 |
| Debounce | 最後の値 | 値が落ち着いた後 |
ThrottleLast は定期的に発行する点が Debounce と異なります。Debounce は値の到着がなくなるのを待ちますが、ThrottleLast は値が連続して届いていても定期的にサンプリングします。
フレームベースの版は ThrottleLastFrame を参照してください。