Ignore incoming stream updates if last callback hasn't finished yet

被刻印的时光 ゝ 提交于 2019-12-13 00:41:03

问题


I have code similar to this.

IPruduceDemUpdates.Subscribe(update => DoUpdate(update));

But what I want to do is something like that.

IPruduceDemUpdates.Subscribe(update => if(NoDoUpadteIsRunning) DoUpdate(update));

So it ignores incoming updates, if the update method is already running. In addition, it should always execute the last update. No matter if it is the last update of the stream or the last for a period of time. Here an example timeline

  • Update 1 starts
  • Update 2 is ignored
  • Update 3 is ignored
  • Update 4 is ignored
  • Update 1 finished
  • Update 4 starts
  • Update 4 finished

Edit

I have solution for skipping

        IPruduceDemUpdates.Subscribe(update =>
        {
            if (_task == null || _task.IsCompleted || _task.IsCanceled || _task.IsFaulted)
                _task = DoUpdate(update);
        });

But I don't know how to be sure, that the last update will process.


回答1:


If DoUpdate is synchronous (which it appears to be in this case), you can use BufferIntrospective from Rxx. It does exactly what you want:

IProduceDemUpdates
    .BufferIntrospective()
    .Where(items => items.Count > 0) // ignore empty buffers
    .Select(items => items[items.Count - 1]) // ignore all but last item in buffer
    .Subscribe(DoUpdate);



回答2:


I'm a bit late to the party, but here's built-in one-liner way to do this. Sample with a TimeSpan.Zero will continuously sample the source and always push the last update - to make this work you need to give Sample it's own thread so that the sampled source can run uninterrupted:

IProduceDemUpdates.Sample(TimeSpan.Zero, NewThreadScheduler.Default)
                  .Subscribe(DoUpdate);

Notes

The thread is reused per subscriber to Sample not generated per event - so no need to worry about a mountain of threads being created. You could also do .Sample(TimeSpan.Zero, new EventLoopScheduler()). The point is that the subscriber is being delivered events on the same thread that Sample is sampling on, so that Sample won't sample the next event until the subscriber is done.

Examples

The following code:

// emits 0,1,2,3,4,5,6,7,8,9
var source = Observable.Interval(TimeSpan.FromSeconds(1)).Take(10); 

source.Sample(TimeSpan.Zero, NewThreadScheduler.Default).Subscribe(x => {
        Console.WriteLine(x);
        Task.Delay(TimeSpan.FromSeconds(3)).Wait();
});

Will typically output:

0
2
5
9

To convince yourself the last update is always received try:

// emit 0,1,2
var source = Observable.Interval(TimeSpan.FromSeconds(1)).Take(3);

source.Sample(TimeSpan.Zero, NewThreadScheduler.Default).Subscribe(x => {
        Console.WriteLine(x);
        Task.Delay(TimeSpan.FromSeconds(10)).Wait();
});

Which will output:

0
2

Caveat

Whatever your approach, note how important it is that you accomplish the slowest operation in the synchronous chain of subscribers attached to Sample. If you have asynchronous subscriptions further downstream (such as an ObserveOn) that include slower operators then you will just be transferring the back-pressure elsewhere.



来源:https://stackoverflow.com/questions/26623988/ignore-incoming-stream-updates-if-last-callback-hasnt-finished-yet

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!