C# 如何确保在响应式扩展中同步调用Select和Subscribe方法
我正在测试RX并创建Stream(),它提供两个相隔1秒的事件C# 如何确保在响应式扩展中同步调用Select和Subscribe方法,c#,system.reactive,C#,System.reactive,我正在测试RX并创建Stream(),它提供两个相隔1秒的事件 private IObservable<string> Stream() { return Observable.Create<string> ( (IObserver<string> observer) => { observer.OnNext("a"); observer.OnNext("b"
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);
我看到每个输入都会调用DoCalc方法两次,然后是Update方法调用两次,DoCalc,DoCalc,Update,Update。相反,我尝试执行DoCalc方法后面跟着Update方法的顺序。重复第二次输入的顺序,以便第二次输入可以建立在第一次输入的结果之上,DoCalc,Update,DoCalc,Update
任何想法首先,我会遵循将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()");
}
void Main()
{
var els=新的EventLoopScheduler();
var dispatcher=new EventLoopScheduler();
流()
.SubscribeOn(els)//TODO:移动到ObserveOn之前的行
.选择(DoCalc)
.ObserveOn(调度员)
.订阅(更新);
}
//在此处定义其他方法和类
私有IObservable流()
{
返回可观察的。创建
(
(IObserver观察员)=>
{
OnNext观察员(“a”);
睡眠(1000);
OnNext观察员(“b”);
observer.OnCompleted();
返回Disposable.Create(()=>Console.WriteLine(“观察者已取消订阅”);
}
);
}
私有字符串DoCalc(字符串val)
{
val.Dump(“DoCalc()”);
睡眠(1000);
返回val;
}
私有无效更新(字符串val)
{
val.Dump(“更新()”);
}
因此,您可以用输出重新发布完整的示例代码。作为单元测试、控制台应用程序或LinqPad示例执行此操作
猜测您的下一个问题,可能是:如何使用投影中的值(
选择
)来帮助计算下一个值?如果需要,请使用Scan
方法;如果只需要最终结果,而不是计算的每个值,请使用Aggregate
方法。能否提供scheduleProvider
的代码?如果我删除了SubscribeOn
和ObserveOn
行,那么我看到了您想要的行为。您可以删除线程吗?在DoCalc中睡眠并尝试运行。你会得到DoCalc,DoCalc,然后是Update,Update,而不是DoCalc,Update,DoCalc,UpdateCorrect。这就是我所期望的。Create委托正在SubscribeOn
计划程序上运行,并将OnNext
直接发送到Select
处理程序,该处理程序是DoUpdate
。DoUpdate的结果是序列的结果投影。然后将这些值调度到最终订阅处理程序。如果您需要这些值进行序列化,那么不要强制在另一个Select投影中执行两组计划,或者执行更新中的操作。如果您可以进一步解释为什么需要这些值,也许我可以提供更好的帮助。e、 g.为什么这些重叠是一个问题?
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()");
}