SubscribeOn和ObserveOn有什么区别


71

我刚刚发现SubscribeOn,这使我想知道是否应该使用它而不是ObserveOn。Google在这里这里带走了我,但两者都没有帮助我改变这种差异:这似乎难以置信。

(在我的上下文中,我在非GUI线程上有事件“即将来临”,在使用事件数据更新控件之前,我需要切换到GUI线程)。


SubscribeOn解决了以下问题:从Winforms或WPF中的多个线程添加事件处理程序会导致异常。
鲍里斯(Boris)

Answers:


54

不久前,我遇到了类似的问题,并问了这个问题。我认为那里的回复(包括评论)将回答您的问题。总结一下:

  • 如果要更新gui线程上的控件,请使用ObserveOn。如果您引用System.Reactive.Windows.Forms.dll它,.ObserveOn(form)那将很方便。
  • SubscribeOn控制实际进行预订的线程。此处解决的问题是,如果您从多个不同的线程中添加事件处理程序,则WinForms和WPF将引发异常。

另外,这篇文章对弄清ObserveOn和之间的关系也非常有帮助SubscribeOn


58

通过SubscribeOn将线程设置为“通过”链,ObserveOn而将线程设置为“通过”链,帮助我理解了这一点。

订阅者线程“通过”和观察者线程“通过”

下面的代码使用可以使用的命名线程。

Thread.CurrentThread.Name = "Main";

IScheduler thread1 = new NewThreadScheduler(x => new Thread(x) { Name = "Thread1" });
IScheduler thread2 = new NewThreadScheduler(x => new Thread(x) { Name = "Thread2" });

Observable.Create<int>(o =>
{
    Console.WriteLine("Subscribing on " + Thread.CurrentThread.Name);
    o.OnNext(1);
    return Disposable.Create(() => {});
})
.SubscribeOn(thread1)
.ObserveOn(thread2)
.Subscribe(x => Console.WriteLine("Observing '" + x + "' on " + Thread.CurrentThread.Name));

上面的输出是:

Subscribing on Thread1 Observing 1 on Thread2

有趣的是,当您注释掉该SubscribeOn行时,输出为:

Subscribing on Main Observing 1 on Thread2

因为默认情况下,订阅会“传递”正在运行的线程(Main此处)。然后ObserveOn“传下去” Thread2

如果您改为注释掉该ObserveOn行,则输出为:

Subscribing on Thread1 Observing 1 on Thread1

因为我们在上“传递”了订阅Thread1,并且默认情况下,该同一个线程也被“传递”并用于运行观察。

在GUI上下文中,要保持响应状态,您需要在GUI线程上完成的工作量最少,但需要在GUI线程上完成订阅(以同步UI更新)。所以你想在GUI线程上观察。


9

根本上的区别在于,subscribeOn强制整个管道由另一个线程处理,但是使用observerOn,只有在您设置管道将在observerOn之后运行的步骤之后,才能在另一个线程中执行observerOn。

    Observable.just(1) 
              .map ---> executed in io thread
              .filter ---> executed in io thread
              .subscribeOn(Scheduers.io)
              .subscribe()

流水线的所有步骤将在另一个线程中执行。

 Observable.just(1) 
              .map ---> executed in Main thread
              .filter ---> executed in Main thread
              .observerOn(Scheduers.io)
              .map ---> executed in New thread
              .filter ---> executed in New thread
              .subscribe()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.