В чем разница между SubscribeOn и ObserveOn - PullRequest
69 голосов
/ 28 сентября 2011

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

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

Ответы [ 3 ]

55 голосов
/ 21 февраля 2015

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

Subscriber thread

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

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

Поскольку по умолчанию подписка «проходит»up ", какой бы поток ни работал (Main здесь).Тогда ObserveOn «пропускает» Thread2.

Если вместо этого вы закомментируете строку ObserveOn, вы получите:

Subscribing on Thread1 Observing 1 on Thread1

Потому чтомы «пропускаем» подписку на Thread1, и по умолчанию этот же поток «пропускается» и используется для запуска наблюдения.

В контексте графического интерфейса, чтобы держать вещи отзывчивыми, вы хотите наименьшее количествоработы, выполненной в потоке графического интерфейса, но вам нужна подписка, выполненная в потоке графического интерфейса пользователя (для синхронизации обновлений пользовательского интерфейса).Итак, вы хотите. Наблюдать за потоком GUI.

53 голосов
/ 28 сентября 2011

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

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

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

5 голосов
/ 05 июня 2016

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

    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()
...