如果上次回调尚未完成,请忽略传入的流更新

时间:2014-10-29 06:29:32

标签: c# system.reactive

我的代码与此类似。

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

但我想做的就是那样。

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

如果更新方法已在运行,则忽略传入更新。 此外,它应始终执行上次更新。无论是流的最后更新还是最后一段时间的更新。这是一个示例时间表

  • 更新1开始
  • 忽略更新2
  • 忽略更新3
  • 忽略更新4
  • 更新1完成
  • 更新4开始
  • 更新4完成

修改

我有跳过的解决方案

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

但我不知道如何确定,最后一次更新将会处理。

2 个答案:

答案 0 :(得分:3)

如果DoUpdate是同步的(在这种情况下似乎是),则可以使用Rxx中的BufferIntrospective。它完全符合您的要求:

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);

答案 1 :(得分:2)

我参加派对有点晚了,但是这里有一条单行方式可以做到这一点。带有Sample的{​​{1}}将不断对源进行抽样并始终推送上次更新 - 为了完成这项工作,您需要为TimeSpan.Zero提供自己的线程,以便采样源可以不间断地运行:

Sample

注释

线程被重用每个订阅者IProduceDemUpdates.Sample(TimeSpan.Zero, NewThreadScheduler.Default) .Subscribe(DoUpdate); 未生成每个事件 - 所以不必担心创建一大堆线程。你也可以做Sample。关键是订阅者正在.Sample(TimeSpan.Zero, new EventLoopScheduler())正在采样的同一线程上发送事件,以便Sample不会对订阅者完成下一个事件进行采样。

实施例

以下代码:

Sample

通常输出:

// 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();
});

为了说服自己最后一次更新,请尝试:

0
2
5
9

将输出:

// 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();
});

买者

无论您的方法是什么,请注意在附加到0 2 的订阅者的同步链中完成最慢操作的重要性。如果您的下游具有异步订阅(例如Sample),其中包含较慢的运算符,那么您只需将反压转移到其他地方。