使用Reactive Extensions(RX),是否可以添加“暂停”命令?

时间:2015-07-11 21:29:23

标签: c# .net system.reactive reactive-programming rx.net

我有一个接收事件流的类,并推出另一个事件流。

所有事件都使用Reactive Extensions(RX)。使用IObserver<T>将传入的事件流从外部源推送到.OnNext,并使用IObservable<T>.Subscribe推出传出的事件流。我在幕后使用Subject<T>来管理它。

我想知道RX中有哪些技术暂时暂停输出。这意味着传入事件将在内部队列中累积,当它们取消暂停时,事件将再次流出。

3 个答案:

答案 0 :(得分:4)

这是我使用Buffer和Window运算符的解决方案:

public static IObservable<T> Pausable<T>(this IObservable<T> source, IObservable<bool> pauser)
{
    var queue = source.Buffer(pauser.Where(toPause => !toPause),
                              _ => pauser.Where(toPause => toPause))
                      .SelectMany(l => l.ToObservable());

    return source.Window(pauser.Where(toPause => toPause).StartWith(true), 
                         _ => pauser.Where(toPause => !toPause))
                 .Switch()
                 .Merge(queue);
}

窗口在订阅时打开,每次都是真实的&#39;从pauser流收到。当暂停提供“假”时,它会关闭。值。

缓冲区执行它应该做的事情,缓冲介于&#39; false&#39;之间的值。并且&#39; true&#39;来自pauser。缓冲区收到“真实”后它输出立即流式传输的IList值。

DotNetFiddle链接:https://dotnetfiddle.net/vGU5dJ

答案 1 :(得分:2)

这是一种相当简单的Rx方式来做你想要的。我创建了一个名为Pausable的扩展方法,它接受一个源可观察源,另一个可观察到boolean,它暂停或恢复了可观察量。

public static IObservable<T> Pausable<T>(
    this IObservable<T> source,
    IObservable<bool> pauser)
{
    return Observable.Create<T>(o =>
    {
        var paused = new SerialDisposable();
        var subscription = Observable.Publish(source, ps =>
        {
            var values = new ReplaySubject<T>();
            Func<bool, IObservable<T>> switcher = b =>
            {
                if (b)
                {
                    values.Dispose();
                    values = new ReplaySubject<T>();
                    paused.Disposable = ps.Subscribe(values);
                    return Observable.Empty<T>();
                }
                else
                {
                    return values.Concat(ps);
                }
            };

            return pauser.StartWith(false).DistinctUntilChanged()
                .Select(p => switcher(p))
                .Switch();
        }).Subscribe(o);
        return new CompositeDisposable(subscription, paused);
    });
}

可以像这样使用:

var xs = Observable.Generate(
    0,
    x => x < 100,
    x => x + 1,
    x => x,
    x => TimeSpan.FromSeconds(0.1));

var bs = new Subject<bool>();

var pxs = xs.Pausable(bs);

pxs.Subscribe(x => { /* Do stuff */ });

Thread.Sleep(500);
bs.OnNext(true);
Thread.Sleep(5000);
bs.OnNext(false);
Thread.Sleep(500);
bs.OnNext(true);
Thread.Sleep(5000);
bs.OnNext(false);

现在,我唯一不能理解你的“传入的事件流是什么意思IObserver<T>”。流是IObservable<T>。观察者不是溪流。听起来你在这里没有做点什么。你能加入你的问题并进一步解释吗?

答案 2 :(得分:1)

您可以使用value模拟暂停/取消暂停。

一旦您的pauseObservable发出'暂停'值,缓冲事件直到pauseObservable发出'unpaused'值。

以下是一个使用BufferUntil implementation by Dave SextonObservable logic by Timothy Shields的例子(前一段时间我自己的问题)

for key, result in cb.get_multi(keys).items():
    print "Value is", result.value

改进空间:可能将两个订阅源(pausedEvents和notPausedEvents)合并为一个。