为了测试这一点,我创建了以下方法来帮助说明事件的顺序:
public void ComplexComputation1(long i)
{
Console.WriteLine("Begin ComplexComputation1");
Thread.Sleep(100);
Console.WriteLine("End ComplexComputation1");
}
public void ComplexComputation2(long i)
{
Console.WriteLine("Begin ComplexComputation2");
Thread.Sleep(100);
Console.WriteLine("End ComplexComputation2");
}
public void FinalAction(long i)
{
Console.WriteLine("Begin FinalAction");
Thread.Sleep(100);
Console.WriteLine("End FinalAction");
}
你的原始代码是这样运行的:
开始最终行动
开始复杂计算1
开始复杂计算2
结束复杂计算2
结束最终行动
结束复杂计算1
开始最终行动
开始复杂计算1
开始复杂计算2
结束最终行动
结束复杂计算2
结束复杂计算1
开始最终行动
开始复杂计算1
开始复杂计算2
结束复杂计算2
结束复杂计算1
结束最终行动
...
强制代码在单个后台线程上按顺序运行很容易。只需使用EventLoopScheduler。
var els = new EventLoopScheduler();
observable.ObserveOn(els).Subscribe(i => ComplexComputation1(i));
observable.ObserveOn(els).Subscribe(i => ComplexComputation2(i));
// next observer must be called only after ComplexComputation1/2 complete on input i
observable.ObserveOn(els).Subscribe(i => FinalAction(i));
这给了:
开始复杂计算1
结束复杂计算1
开始复杂计算2
结束复杂计算2
开始最终行动
结束最终行动
开始复杂计算1
结束复杂计算1
开始复杂计算2
结束复杂计算2
开始最终行动
结束最终行动
开始复杂计算1
结束复杂计算1
开始复杂计算2
结束复杂计算2
开始最终行动
结束最终行动
但是你一介绍Scheduler.Default就不行了。
或多或少简单的选择是这样做:
var cc1s = observable.ObserveOn(Scheduler.Default).Select(i => { ComplexComputation1(i); return Unit.Default; });
var cc2s = observable.ObserveOn(Scheduler.Default).Select(i => { ComplexComputation2(i); return Unit.Default; });
observable.Zip(cc1s.Zip(cc2s, (cc1, cc2) => Unit.Default), (i, cc) => i).Subscribe(i => FinalAction(i));
按预期工作。
你会得到这样一个很好的序列:
开始复杂计算1
开始复杂计算2
结束复杂计算1
结束复杂计算2
开始最终行动
结束最终行动
开始复杂计算2
开始复杂计算1
结束复杂计算2
结束复杂计算1
开始最终行动
结束最终行动
开始复杂计算1
开始复杂计算2
结束复杂计算2
结束复杂计算1
开始最终行动
结束最终行动