在Reactive Extensions中一次处理一个事件

时间:2013-10-04 21:27:46

标签: c# system.reactive

让我们考虑以下流

  SomeState state = new SomeState().

 _refreshFiberStream =
    Stream()
    .SubscribeOn(new EventLoopScheduler()) 
    .Select(DoCalc)
    .ObserveOn(DispatcherScheduler.Current)
    .Subscribe(Update);

DoCalc方法将投射到输入并消耗“状态”。并将结果输出提供给Update方法,这将修改'状态'。如果有新事件发生,它应该根据上次事件的最后更新状态,并根据该事件进行项目。

我正在寻找一种总是按顺序执行事件的方法。例如,如果我有三个事件,我正在寻找一种方式,以便它们在DoCalc中执行,Update后跟DoCalc,Update后跟DoCalc,Update。

相反,我看到的是DoCalc,DoCalc,Update,Update,DoCalc,Update,即它们从不按顺序运行。

有没有办法可以在Rx中强制执行它

1 个答案:

答案 0 :(得分:2)

我发现一方面需要执行顺序,另一方面调度到另一个线程之间存在冲突。我的建议是将Update分为两部分:

  1. 需要按顺序执行的部分(更新)
  2. 需要调度的部分(Dispatch)
  3. 然后您可以按顺序调用Do(Update),并在调度程序上调用Subscribe(Dispatch)

    var result =
        Stream()
            .SubscribeOn(new EventLoopScheduler())
            .Select(DoCalc)
            .Do(Update)
            .ObserveOn(DispatcherScheduler.Current)
            .Subscribe(Dispatch);
    

    结果序列是这样的(“更新n”之后的任何时间都可能发生“调度n”调用):

        Select a
        Update a
        Select b
        Update b
        Dispatch a
        Dispatch b
    

    我想另一种方法是使用ManualResetEvent,这表明下一个DoCalc只能在更新发生后才能继续。您可以通过将ManualResetEvent.WaitOne添加到DoCalc并将ManualResetEvent.Set添加到更新来执行此操作:

    private ManualResetEvent _wait = new ManualResetEvent(true);
    
    private string DoCalc(string input)
    {
        _wait.WaitOne();
        Console.WriteLine("Selected {0}", input);
        _wait.Reset();
        return input;
    }
    
    private void Update(string input)
    {
        Console.WriteLine("Update {0}", input);
        _wait.Set();
    }
    

    这第二种方法“有效”,但这样的线程阻塞让我感到不安 - 它似乎与反应式编程的交叉目的有效。当然,同样地,it's best to avoid introducing state, if possible.