好的,事实证明,默认情况下,ReplaySubject
使用Scheduler.CurrentThread
.
如果我明确地将 设置ReplaySubject
为使用Scheduler.Immediate
or Scheduler.ThreadPool
,那么它会按预期工作。
var replaySubject = new ReplaySubject<string>(1, Scheduler.Immediate);
replaySubject.OnNext("This can never block... surely?");
var s = replaySubject.First();
Debug.WriteLine(s);
我仍然需要调查 UI 线程是如何在我的特定场景中陷入这种混乱的,但现在,这解决了这个问题。
--- 编辑 ---
OK, on further investigation, it turns out that the above piece of code for most of the time is initiated on a ThreadPool thread. Even though, when it reaches the code, it is on the Dispatcher thread, Scheduler.CurrentThread puts the ReplaySubject back onto the original ThreadPool thread.
However, in the scenario where it is breaking, everything starts with the user clicking a button. This is obviously on the UI thread, and when it reaches this piece of code, Scheduler.CurrentThread is now the UI thread, and since we are already on the UI thread, we have a deadlock. First is waiting for the ReplaySubject to pump - but the pump is queued up behind the current action. Subtle and something of which to be aware.