閱讀explanation爲什麼調度程序:立即與CurrentThread
Observable.Return(5)
.Repeat()
.Take(1)
從來沒有完成,但
Observable.Return(5, Scheduler.CurrentThread)
.Repeat()
.Take(1)
按預期工作後。我仍然困惑,我不知道爲什麼currentThread
實際上解決了這個問題。有人可以給出明確的解釋嗎?
閱讀explanation爲什麼調度程序:立即與CurrentThread
Observable.Return(5)
.Repeat()
.Take(1)
從來沒有完成,但
Observable.Return(5, Scheduler.CurrentThread)
.Repeat()
.Take(1)
按預期工作後。我仍然困惑,我不知道爲什麼currentThread
實際上解決了這個問題。有人可以給出明確的解釋嗎?
Ned Stoyanov在上述評論中提供的link由Dave Sexton提供了很好的解釋。
我會試着說明它有點不同。以RecursiveTest方法中發生遞歸調用爲例。
public class RecursiveTest()
{
private bool _isDone;
public void RecursiveMethod()
{
if (!_isDone)
{
RecursiveMethod();
// Never gets here...
_isDone = true;
}
}
}
你可以很容易地看到,這將無限遞歸(直到StackOverflowException),因爲_isDone將永遠不會被設置爲true。這是一個過分簡化的例子,但基本上你的第一個例子是怎麼回事。
這是Dave Sexton對第一個例子中發生的情況的解釋。
默認情況下,Return使用ImmediateScheduler調用OnNext(1),然後使用 OnCompleted()。重複沒有引入任何併發性,所以它立即看到 OnCompleted,然後立即重新訂閱Return。 由於Return中沒有蹦牀,這種模式會自動重複, 無限期地阻止當前線程。調用這個 訂閱永遠不會返回。
換句話說,由於無限循環的重入,初始流動永遠不會完全完成。所以我們需要一種方法來完成最初的流程而不需要重新進入。
讓我們回到上面這篇文章中的RecursiveTest示例,避免無限遞歸的解決方案是什麼?在執行RecursiveMethod之前,我們需要RecursiveMethod來完成它的流程。要做到這一點的方法之一是有一個隊列和排隊這樣的調用RecursiveMethod:
public void RecursiveMethod()
{
if (!_isDone)
{
Enqueue(RecursiveMethod);
_isDone = true;
}
}
這種方式,初始流動將完成,_isDone將被設置爲true,何時RecursiveMethod下一個電話是執行,沒有什麼會得到執行,避免無限遞歸。這幾乎是Scheduler.CurrentThread對第二個例子的作用。
讓我們來看看戴夫·塞克斯頓如何解釋你的第二個例子是如何工作的:
這裏,返回使用CurrentTheadScheduler調用OnNext(1),然後 OnCompleted()。重複不會引入任何併發性,所以它立即看到 OnCompleted,然後立即重新訂閱Return; 但是,此第二次訂閱返回計劃在蹦牀上的(內部) 操作,因爲它仍在 上執行第一個計劃(外部)操作的OnCompleted回叫,因此 重複不會立即發生。這允許重複返回 一次性到Take,最終調用OnCompleted,通過處理重複取消 重複,並最終返回訂閱 的呼叫。
我的例子再一次被簡化,使其易於理解,它不完全是如何工作的。 Here you can see調度程序是如何工作的。它使用他們所稱的蹦牀,它基本上是一個確保沒有可重入呼叫的隊列。因此所有的調用都是在同一個線程上依次序列化。通過這樣做,可以完成初始流程,避免無限重入循環。
希望這有點更清楚:)
感謝這個答案,它對我來說非常清楚。 – GiantSquid
我已經嘗試過兩種方法,他們都完成對我來說很好。你可以請張貼重現問題的代碼嗎? – Enigmativity
請參閱此[post](https://social.msdn.microsoft.com/Forums/zh-CN/7f75482f-eff2-4938-9491-47fe870989e8/currentthreadscheduler-vs-immediatescheduler?forum=rx)。 –
@ Enigmativity第一個在Linqpad中鎖定我,儘管它打印出值 –