簡體   English   中英

節流Rx.Observable而不跳過值

[英]Throttle Rx.Observable without skipping values

如果其他人跟隨太快,則Throttle方法會從可觀察序列中跳過值。 但我需要一種方法來延遲它們。 也就是說,我需要在項目之間設置最小延遲,而不是跳過任何項目

實際例子:有一個Web服務可以接受不超過一秒的請求; 有一個用戶可以單獨或批量添加請求。 沒有Rx,我將創建一個列表和一個計時器。 當用戶添加請求時,我會將它們添加到列表中。 在計時器事件中,我將檢查列表是否為空。 如果不是,我將發送請求並刪除相應的項目。 隨着鎖和所有的東西。 現在,使用Rx,我可以創建Subject ,在用戶添加請求時添加項目。 但我需要一種方法來確保Web服務不會因應用延遲而泛濫。

我是Rx的新手,所以也許我錯過了一些明顯的東西。

使用EventLoopScheduler有一種相當簡單的方法可以做你想做的EventLoopScheduler

我從一個observable開始,每隔0到3秒就會隨機產生一次值。

var rnd = new Random();

var xs =
    Observable
        .Generate(
            0,
            x => x < 20,
            x => x + 1,
            x => x,
            x => TimeSpan.FromSeconds(rnd.NextDouble() * 3.0));

現在,要立即生成此輸出值,除非最后一個值在一秒鍾之內,我這樣做:

var ys =
    Observable.Create<int>(o =>
    {
        var els = new EventLoopScheduler();
        return xs
            .ObserveOn(els)
            .Do(x => els.Schedule(() => Thread.Sleep(1000)))
            .Subscribe(o);
    });

這有效地觀察了EventLoopScheduler上的EventLoopScheduler ,然后在每個OnNext之后將其置於休眠狀態1秒,這樣它只能在喚醒之后開始下一個OnNext

我測試它使用此代碼:

ys
    .Timestamp()
    .Select(x => x.Timestamp.Second + (double)x.Timestamp.Millisecond/1000.0)
    .Subscribe(x => Console.WriteLine(x));

我希望這有幫助。

我想建議使用Observable.Zip的方法:

// Incoming requests
var requests = new[] {1, 2, 3, 4, 5}.ToObservable();

// defines the frequency of the incoming requests
// This is the way to emulate flood of incoming requests.
// Which, by the way, uses the same approach that will be used in the solution
var requestsTimer = Observable.Interval(TimeSpan.FromSeconds(0.1)); 
var incomingRequests = Observable.Zip(requests, requestsTimer, (number, time) => {return number;});
incomingRequests.Subscribe((number) =>
{
    Console.WriteLine($"Request received: {number}");
});

// This the minimum interval at which we want to process the incoming requests
var processingTimeInterval = Observable.Interval(TimeSpan.FromSeconds(1));

// Zipping incoming requests with the interval
var requestsToProcess = Observable.Zip(incomingRequests, processingTimeInterval, (data, time) => {return data;});

requestsToProcess.Subscribe((number) =>
{
    Console.WriteLine($"Request processed: {number}");
});

一個簡單的擴展方法怎么樣:

public static IObservable<T> StepInterval<T>(this IObservable<T> source, TimeSpan minDelay)
{
    return source.Select(x => 
        Observable.Empty<T>()
            .Delay(minDelay)
            .StartWith(x)
    ).Concat();
}

用法:

var bufferedSource = source.StepInterval(TimeSpan.FromSeconds(1));

我正在玩這個並發現.Zip(如前所述)是最簡單的方法:

var stream = "ThisFastObservable".ToObservable();
var slowStream = 
    stream.Zip(
        Observable.Interval(TimeSpan.FromSeconds(1)), //Time delay 
        (x, y) => x); // We just care about the original stream value (x), not the interval ticks (y)

slowStream.TimeInterval().Subscribe(x => Console.WriteLine($"{x.Value} arrived after {x.Interval}"));

輸出:

T arrived after 00:00:01.0393840
h arrived after 00:00:00.9787150
i arrived after 00:00:01.0080400
s arrived after 00:00:00.9963000
F arrived after 00:00:01.0002530
a arrived after 00:00:01.0003770
s arrived after 00:00:00.9963710
t arrived after 00:00:01.0026450
O arrived after 00:00:00.9995360
b arrived after 00:00:01.0014620
s arrived after 00:00:00.9993100
e arrived after 00:00:00.9972710
r arrived after 00:00:01.0001240
v arrived after 00:00:01.0016600
a arrived after 00:00:00.9981140
b arrived after 00:00:01.0033980
l arrived after 00:00:00.9992570
e arrived after 00:00:01.0003520

如何使用可觀察的計時器從阻塞隊列中獲取? 下面的代碼未經測試,但應該讓您了解我的意思......

//assuming somewhere there is 
BlockingCollection<MyWebServiceRequestData> workQueue = ...

Observable
  .Timer(new TimeSpan(0,0,1), new EventLoopScheduler())
  .Do(i => myWebService.Send(workQueue.Take()));

// Then just add items to the queue using workQueue.Add(...)

考慮使用緩沖區。

http://msdn.microsoft.com/en-us/library/hh212130(v=vs.103).aspx

正如名稱所示,它在可觀察的事件流中緩沖元素而不“丟棄”它們中的任何一個。

-G

.Buffer(TimeSpan.FromSeconds(0.2)).Where(i => i.Any())
.Subscribe(buffer => 
{
     foreach(var item in buffer) Console.WriteLine(item)
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM