Какая разница между SubscribeOn и ObserveOn

Я только что обнаружил SubscribeOn, что заставляет меня задаться вопросом, следует ли мне использовать это вместо ObserveOn. Google взял меня здесь и здесь, но ни один из них не помог мне grok разница: кажется невероятно тонким.

(В моем контексте у меня есть события, которые "появляются" в потоке без gui, и мне нужно переключиться на поток gui, прежде чем использовать данные событий для обновления элементов управления).

Ответ 1

У меня была аналогичная проблема некоторое время назад и спросили этот вопрос об этом. Я думаю, что ответы (включая комментарии) будут отвечать на ваш вопрос. Подводя итог:

  • Если вы хотите обновлять элементы управления потоком gui, используйте ObserveOn. Если вы ссылаетесь на System.Reactive.Windows.Forms.dll, вы получаете .ObserveOn(form), который удобен.
  • SubscribeOn управляет потоком, на котором происходит фактический вызов подписки. Проблема, решаемая здесь, заключается в том, что WinForms и WPF будут генерировать исключения, если вы добавите обработчики событий из нескольких разных потоков.

Кроме того, это сообщение было очень полезно при определении связи между ObserveOn и SubscribeOn.

Ответ 2

Это помогло мне понять это, подумав о SubscribeOn как о том, что поток "передал" цепочку и ObserveOn как настройку потока "передал" цепочку.

Subscriber thread "passed up" and Observer thread "passed down"

В приведенном ниже коде используются именованные темы, с которыми вы можете играть.

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, и по умолчанию этот же поток "передается вниз" и используется для запуска наблюдения.

Ответ 3

В основном отличия заключаются в том, что subscribeOn заставляет весь конвейер обрабатываться другим потоком, но с observerOn только шаги в вашем конвейере определяют после того, как observerOn будет работать в другом потоке только после того, как вы его установили, будет выполняться в другом потоке.

    Observable.just(1) 
              .map ---> executed in Main thread
              .filter ---> executed in Main 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()