Dot-Net

反應式擴展:節流/樣本與不同的時間間隔

  • February 25, 2020

我有一個IObservable以隨機間隔產生值的,我想限制這個序列。我發現的一件事是Throttle運營商對“節流”的定義與我的不同。

Throttle僅在指定的時間間隔過後才產生值**(**它產生最後看到的值)。我認為節流意味著在指定的時間間隔內產生值(當然,除非有沉默)。

說,我希望Observable.Interval(100).Select((_,i) => i).Throttle(200)產生(以任何性能/時序問題為模)偶數,因為我將其限制為“半速”。然而,這個序列根本沒有產生任何價值,因為從來沒有一段長度為 200 的靜默期。

所以,我發現這Sample實際上是我想要的“節流”行為。Observable.Interval(100).Select((_,i) => i).Sample(200)產生(再次以任何性能/時序問題為模)偶數序列。

但是,我還有另一個問題:間隔會有所不同,具體取決於最後一個“採樣”值。我想要的是編寫一個如下所示的運算符:

public static IObservable<T> Sample<T>(this IObservable<T> source, Func<T, TimeSpan> intervalSelector);

intervalSelector參數產生下一個樣本的間隔,第一個樣本……要麼取自第一個值,要麼取自附加參數,我不在乎。

我試著寫這個,但我最終得到了一個大而復雜的結構,它不能很好地工作。我的問題是,我可以使用現有的運營商(也就是單線)來建構它嗎?

幾個小時後,在上面睡了一會兒,我明白了。

public static IObservable<T> Sample<T>(this IObservable<T> source, Func<T, TimeSpan> intervalSelector)
{
   return source.TimeInterval()
                .Scan(Tuple.Create(TimeSpan.Zero, false, default(T)), (acc, v) =>
                {
                    if(v.Interval >= acc.Item1)
                    {
                        return Tuple.Create(intervalSelector(v.Value), true, v.Value);
                    }
                    return Tuple.Create(acc.Item1 - v.Interval, false, v.Value);
                })
                .Where(t => t.Item2)
                .Select(x => x.Item3);
}

這可以按我的意願工作:每次它產生一個 valuex時,它都會停止產生值,直到intervalSelector(x)時間過去。

引用自:https://stackoverflow.com/questions/3490442