To test this out I created the following methods to help illustrate the sequence of events:
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");
}
Your original code ran like this:
Begin FinalAction
Begin ComplexComputation1
Begin ComplexComputation2
End ComplexComputation2
End FinalAction
End ComplexComputation1
Begin FinalAction
Begin ComplexComputation1
Begin ComplexComputation2
End FinalAction
End ComplexComputation2
End ComplexComputation1
Begin FinalAction
Begin ComplexComputation1
Begin ComplexComputation2
End ComplexComputation2
End ComplexComputation1
End FinalAction
...
It's easy to enforce the code to run in sequence on a single background thread. Just use an 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));
That gives:
Begin ComplexComputation1
End ComplexComputation1
Begin ComplexComputation2
End ComplexComputation2
Begin FinalAction
End FinalAction
Begin ComplexComputation1
End ComplexComputation1
Begin ComplexComputation2
End ComplexComputation2
Begin FinalAction
End FinalAction
Begin ComplexComputation1
End ComplexComputation1
Begin ComplexComputation2
End ComplexComputation2
Begin FinalAction
End FinalAction
But as soon as you introduce Scheduler.Default this doesn't work.
The more-or-less simple option is to do this:
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));
That works as expected.
You get a nice sequence like this:
Begin ComplexComputation1
Begin ComplexComputation2
End ComplexComputation1
End ComplexComputation2
Begin FinalAction
End FinalAction
Begin ComplexComputation2
Begin ComplexComputation1
End ComplexComputation2
End ComplexComputation1
Begin FinalAction
End FinalAction
Begin ComplexComputation1
Begin ComplexComputation2
End ComplexComputation2
End ComplexComputation1
Begin FinalAction
End FinalAction