C# ObserveOn with Scheduler.NewThread如果观察者';s OnNext被阻止并继续

C# ObserveOn with Scheduler.NewThread如果观察者';s OnNext被阻止并继续,c#,.net,linq,system.reactive,C#,.net,Linq,System.reactive,有人能帮我解释一下为什么当我“阻塞并继续”观察者的onNext序列订阅了一个带有时间可观察序列的缓冲区时,Scheduler.NewThread不再适用了 例如: 如果我通过 var query = from number in Enumerable.Range(1,200) select SnoozeNumberProduction(number); var observableQuery = query.ToObservable(); var bufferedSeq

有人能帮我解释一下为什么当我“阻塞并继续”观察者的onNext序列订阅了一个带有时间可观察序列的缓冲区时,Scheduler.NewThread不再适用了

例如:

如果我通过

var query = from number in Enumerable.Range(1,200)
            select SnoozeNumberProduction(number);

var observableQuery = query.ToObservable();
var bufferedSequence = observableQuery.Buffer(TimeSpan.FromSeconds(2));
其中,打盹延迟了250毫秒的数字生成

static int SnoozeNumberProduction(Int32 number)
{
    Thread.Sleep(250);
    return number;
}
现在,如果稍后我使用“ObserveOn(Scheduler.NewThread)”订阅bufferedSequence,这样我就可以使用Console.ReadKey阻塞第四个缓冲区

Random random = new Random();
Int32 count = 0;
bufferedSequence.ObserveOn(Scheduler.NewThread).Subscribe(list =>
{
    Console.WriteLine("({0}) Numbers from {1}-{2} produced on Thread ID {3}", list.Count, list[0], list[list.Count -1], Thread.CurrentThread.ManagedThreadId);

    Thread.Sleep(1000);
    count++;
    if (count == 4)
    {
        Console.WriteLine("count reached to 4, blocking ... press any key to continue ");
        Console.ReadKey(); // Block and build up the queue
    }

    Console.WriteLine("Woken " + list[0] + " - " + list[list.Count - 1]);
});
在本例中,如果我在大约10秒后按任意键,我会看到接下来的几个缓冲区在同一ManagedThread上执行,即使在ObserveOn中提到了Scheduler.NewThread。有人能解释一下这种行为吗

样本输出:

(7) Numbers from 1-7 produced on Thread ID 12
Woken 1 - 7
(9) Numbers from 8-16 produced on Thread ID 14
Woken 8 - 16
(8) Numbers from 17-24 produced on Thread ID 15
Woken 17 - 24
(8) Numbers from 25-32 produced on Thread ID 16
count reached to 4, blocking ... press any key to continue
Woken 25 - 32
(8) Numbers from 33-40 produced on Thread ID **16**
Woken 33 - 40
(8) Numbers from 41-48 produced on Thread ID **16**
Woken 41 - 48
(8) Numbers from 49-56 produced on Thread ID **16**
Woken 49 - 56
(8) Numbers from 57-64 produced on Thread ID **16**
Woken 57 - 64
(8) Numbers from 65-72 produced on Thread ID **16**
Woken 65 - 72
(8) Numbers from 73-80 produced on Thread ID **16**
Woken 73 - 80
(8) Numbers from 81-88 produced on Thread ID **16**
Woken 81 - 88
(8) Numbers from 89-96 produced on Thread ID **16**

ObserveOn
本身就是合成序列中的一个层,唯一的任务是切换到另一个调度程序。但是,您的睡眠发生在
Select
上的
IEnumerable
上。然后使用
ToObservable
将该序列转换为
ioobservable
,默认为
Dispatcher.CurrentThread

只有在这一点上,您才可以为每个项目切换到另一个线程。如果将其更改为:

var query = from number in Enumerable.Range(1,200).ToObservable(Dispatcher.NewThread)
            select SnoozeNumberProduction(number);

var bufferedSequence = query.Buffer(TimeSpan.FromSeconds(2));
现在枚举发生在一个新线程上,由于您没有做任何更改,它将保持在那里

实际上有一个
Observable.Range
,它以
ioobservable
开始,并采用可选的
IDispatcher
。但是,我假设您的源代码实际上不是可枚举的。如果是这样的话,以下是等价物:

var query = from number in Observable.Range(1,200, Dispatcher.NewThread)
            select SnoozeNumberProduction(number);

var bufferedSequence = query.Buffer(TimeSpan.FromSeconds(2));

我将这个问题交叉发布到MSDN Rx论坛,并了解到这是出于效率原因


您在订阅中阻止了对OnNext的呼叫。 ObserveOn操作符确保在当前线程上调用OnNext的次数尽可能多。 ObserveOn操作符重用当前线程,按顺序调用OnNext,以获取当前可用的尽可能多的值由于您在Subscribe中阻塞,对OnNext的多个调用将累积。解除阻止后,排队的调用将在同一线程上执行。我相信这是为了避免在不必要的情况下为每个通知创建新线程的开销。