在阅读了explanation之后,为什么

Observable.Return(5)
  .Repeat()
  .Take(1)

从未完成,但是
Observable.Return(5, Scheduler.CurrentThread)
  .Repeat()
  .Take(1)

可以正常工作。我仍然很困惑,我不知道为什么currentThread实际上可以解决问题。有人可以给出清楚的解释吗?

最佳答案

内德·斯托亚诺夫(Ned Stoyanov)在上述评论中提供的link对戴夫·塞克斯顿(Dave Sexton)进行了很好的解释。
我将尝试以不同的方式说明它。以本示例为例,其中RecursiveMethod中发生了递归调用。

public class RecursiveTest()
{
    private bool _isDone;

    public void RecursiveMethod()
    {
        if (!_isDone)
        {
            RecursiveMethod();

           // Never gets here...
           _isDone = true;
        }
    }
}
您可以轻松地看到这将无限期递归(直到StackOverflowException),因为_isDone永远不会设置为true。这是一个过于简化的示例,但基本上是您的第一个示例所进行的操作。
这是Dave Sexton的解释,描述了第一个示例中发生的情况。

换句话说,由于折返的无限循环,初始流程永远不会完全完成。因此,我们需要一种无需重新输入即可完成初始流程的方法。
让我们回到本文上面的RecursiveTest示例,避免无限递归的解决方案是什么?在再次执行RecursiveMethod之前,我们将需要RecursiveMethod完成其流程。执行此操作的一种方法是使队列排队,并使对RecursiveMethod的调用排队,如下所示:
public void RecursiveMethod()
{
    if (!_isDone)
    {
        Enqueue(RecursiveMethod);
        _isDone = true;
    }
}
这样,初始流程将完成,_isDone将设置为true,并且在执行下一次对RecursiveMethod的调用时,将不再执行任何操作,从而避免了无限递归。这几乎是Scheduler.CurrentThread将对第二个示例执行的操作。
让我们看看Dave Sexton如何解释第二个示例的工作原理:

再次重申,我的示例确实经过简化,以使其易于理解,并且其运行方式也不尽相同。 Here you can see调度程序的真正工作方式。它使用他们所谓的蹦床,基本上就是一个确保没有重入调用的队列。因此,所有调用在同一线程上一个接一个地序列化。这样,可以完成初始流程,从而避免了无限重入循环。
希望这会更清楚:)

10-06 10:01