Rx - CombineLatest Queue

时间:2016-10-12 20:43:13

标签: c# .net system.reactive

我正在尝试使用Rx实现Queue之类的功能(我知道我可以使用Queue + Locking来完成它,但是尝试学习+使用Rx,因为我没有很多机会使用它)。

功能是,我想对要执行的事件采取一些操作,但只希望一次处理一个事件,一旦完成,处理下一个/最后一个事件(如果它是新的)。

这就是我现在所拥有的(使用可观察的递增标记,因此我可以DistinctUntilChanged,但这感觉就像一个黑客)。

        // Some source
        var events = new Subject<string>();
        events.Subscribe(s => Console.WriteLine("Event: " + s));

        // How can I get rid of this
        var counter = 0;

        var flag = new Subject<int>();
        flag.Subscribe(i => Console.WriteLine("Flag: " + i));
        var combined = events
            .CombineLatest(flag, (s, i) => new {Event = s, Flag = i});

        var worker = combined
            .DistinctUntilChanged(arg => arg.Flag)
            .DistinctUntilChanged(arg => arg.Event);

        worker.Subscribe(x => Console.WriteLine("\r\nDo Work: " + x.Event + "\r\n"));


        flag.OnNext(counter++); // Ready
        events.OnNext("one"); // Idle, Start eight

        events.OnNext("two");
        events.OnNext("three");
        events.OnNext("four");

        events.OnNext("five"); // Process
        flag.OnNext(counter++); // Finished one, start five

        events.OnNext("six");
        events.OnNext("seven");

        events.OnNext("eight"); // Idle, Start eight
        flag.OnNext(counter++); // Finished five, start eight
        flag.OnNext(counter++); // Finished eight

        events.OnNext("nine"); // Should be processed

如果您运行此代码,您将看到最后一个事件未得到处理,即使该actor处于空闲状态。

感觉我在这里错过了什么......

目前我正在考虑以某种方式使用Observables Observables ......但是在过去几个小时内一直试图解决这个问题: - (

修改

通过将主题更改为ReplaySubject

来管理
        var events = new ReplaySubject<string>(1);

并引入了另外一个变量,但看起来像另一个黑客,但它确实让我摆脱了反击。

        string lastSeen = null;
        flag.Select(x => events.Where(s => s != lastSeen).Take(1))
            .Subscribe(x =>
                x.Subscribe(s =>
                {
                    lastSeen = s;
                    Console.WriteLine(s);
                })
            );

如果有人知道更好的方法,我可以摆脱string lastSeen或简化我的嵌套/订阅,这将是很棒的。

1 个答案:

答案 0 :(得分:1)

如果您愿意混合使用TPL DataFlow Blocks,您可以按照自己的意愿行事。虽然我必须说它有点不Rxish。

var source = Observable.Interval(TimeSpan.FromSeconds(1));
var queue = new BroadcastBlock<long>(null);
var subscription = queue.AsObservable().DistinctUntilChanged().Subscribe(l =>
{
    Thread.Sleep(2500);
    Console.WriteLine(l);
});

source.SubscribeOn(ThreadPoolScheduler.Instance).Subscribe(queue.AsObserver());

BroadcastBlock是仅保留最后一个值的队列。 TPL DataFlow Blocks对Rx有很好的支持。所以我们可以订阅事件并将其放入BroadcastBlock,然后订阅BroadcastBlock。