有人可以帮助解释为什么当我“阻止并继续”观察者的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));
SnoozeNumberProduction将数字生成延迟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秒左右后按任意键,我会看到即使在ObserveOn中提到Scheduler.NewThread时,下一个缓冲区也会在同一个ManagedThread上执行。请有人帮忙解释一下这种行为吗?
示例输出:
(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**
答案 0 :(得分:2)
ObserveOn
本身就是您编写的序列中的一个层,唯一的工作就是交换到另一个调度程序。但是,您的睡眠发生在Select
IEnumerable
上。然后使用IObservable
将该序列转换为ToObservable
,默认为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
以IObservable
开头并带有可选IDispatcher
。但是,我认为您的来源实际上不是Enumerable.Range
。如果是的话,这就等同于:
var query = from number in Observable.Range(1,200, Dispatcher.NewThread)
select SnoozeNumberProduction(number);
var bufferedSequence = query.Buffer(TimeSpan.FromSeconds(2));
答案 1 :(得分:0)
我将此问题发布到MSDN Rx论坛http://social.msdn.microsoft.com/Forums/en-US/rx/thread/52e72a11-9841-4571-b86d-f805d3aeb7b5并了解到这是出于效率原因
您正在阻止订阅中对OnNext的调用。 ObserveOn运算符确保在当前线程上尽可能多地调用OnNext。 ObserveOn运算符重复使用当前线程按顺序调用OnNext,以获取当前可用的值。 由于您在订阅中阻止,因此会多次调用OnNext。解除阻塞后,排队的调用将在同一个线程上执行。我认为这是为了避免在没有必要时为每个通知创建新线程的开销。