如何确保在Reactive Extensions中同步调用Select和Subscribe方法

时间:2013-10-03 19:25:37

标签: c# system.reactive

我正在测试尝试测试RX并创建Stream(),它提供两个相隔1秒的事件。

private IObservable<string> Stream()
{
    return Observable.Create<string>
    (
        (IObserver<string> observer) =>
        {
            observer.OnNext("a");
            observer.OnNext("b");
            observer.OnCompleted();         
            return Disposable.Create(() => Console.WriteLine("Observer has unsubscribed"));
        }
    );
}

  _refreshFiberStream =
    Stream()
    .SubscribeOn(schedulerProvider.EventLoop) 
    .Select(DoCalc)
    .ObserveOn(schedulerProvider.Dispatcher)
    .Subscribe(Update);

和ScheduleProvider

 public sealed class SchedulerProvider : ISchedulerProvider
  {
    public IScheduler Dispatcher
    {
      get { return DispatcherScheduler.Current; }
    }

    public IScheduler EventLoop
    {
      get { return new EventLoopScheduler(); }
    }
    // ...
  }

我看到每个输入都会调用DoCalc方法两次,然后调用两次Update方法,DoCalc,DoCalc,Update,Update。相反,我试图按顺序排序DoCalc方法,然后是Update方法。重复序列进行第二次输入,因此第二个输入可以构建在第一个输入,DoCalc,Update,DoCalc,Update

的结果之上

任何想法

1 个答案:

答案 0 :(得分:0)

首先,我会遵循在最终的Subscribe方法之前放置SubscribeOn / ObserveOn对的模式。这样可以省去很多毛发。

_refreshFiberStream = Stream()
    .Select(DoCalc)
    //Always in this pattern
    .SubscribeOn(schedulerProvider.EventLoop) //SubscribeOn right before ObserveOn (or before Subscribe if no ObserveOn is used)
    .ObserveOn(schedulerProvider.Dispatcher)  //ObserveOn right before Subscribe
    .Subscribe(Update);                       //Subscribe Last

接下来,如果我重新创建您的示例并添加丢失的代码,我会得到正确/预期的输出。

void Main()
{
    var els = new EventLoopScheduler();
    var dispatcher = new EventLoopScheduler();

    Stream()
        .SubscribeOn(els) //TODO: Move to line just before ObserveOn
        .Select(DoCalc)
        .ObserveOn(dispatcher)
        .Subscribe(Update); 
}

// Define other methods and classes here
private IObservable<string> Stream()
{
    return Observable.Create<string>
    (
        (IObserver<string> observer) =>
        {
            observer.OnNext("a");
            Thread.Sleep(1000);
            observer.OnNext("b");
            observer.OnCompleted();         
            return Disposable.Create(() => Console.WriteLine("Observer has unsubscribed"));
        }
    );
}
private string DoCalc(string val)
{
    val.Dump("DoCalc()");
    Thread.Sleep(1000);
    return val;
}
private void Update(string val)
{
    val.Dump("Update()");
}

那么你可以用输出重新发布你的完整示例代码吗?这可以作为单元测试,控制台应用程序或LinqPad样本。

猜测你的下一个问题,可能是:我如何使用前一个值的投影值(Select)来帮助计算下一个值?如果您想要running set of calculations,请使用Scan方法,如果您只想要最终结果而不是计算每个值,请使用Aggregate方法。