Исключение между потоками при использовании RX Throttle - PullRequest
5 голосов
/ 07 января 2012

Я получаю

Недопустимый доступ к потокам.

При использовании RX Throttle

Вот мой код:

        yObs.SubscribeOnDispatcher()
            .DistinctUntilChanged()
            .Throttle(TimeSpan.FromMilliseconds(33))
            .SkipWhile(y => !_isDragging)
            .Subscribe(y =>
                           {
                               // Exception when trying to access image
                               image.RenderTransform = new CompositeTransform() { TranslateY = -y };
                               _vm.UpdateContentDrag(y / image.ActualHeight * 100);
                           });

Но если я опущу газ, все будет работать.

Насколько я понимаю, Throttle использует пул потоков, поэтому OnNext не происходит в потоке пользовательского интерфейса. Но SubscribeOnDispatcher должен перенаправить его обратно в поток пользовательского интерфейса. Не должно ли это?

Ответы [ 2 ]

12 голосов
/ 10 января 2012

Ваше понимание SubscribeOnDispatcher неверно.Прежде всего, давайте различать два оператора * On:

  • SubscribeOn * - Запускает (не) логику подписки в указанном планировщике.Используется редко, если только вы не играете с Observable.Create и т. Д.
  • ObserveOn * - запускает сообщения наблюдателя (OnNext, OnError, OnCompleted) в указанном планировщике.Чаще всего используется для синхронизации пользовательского интерфейса при запуске «обработчиков событий», передаваемых в Subscribe.

Для того, чтобы ваш пример работал, вы также должны придерживаться оператора ObserveOn, который используется ниже в запросе.Мы рекомендуем сделать это прямо перед финальным звонком.Внутри запроса параллелизм может быть введен такими операторами, как Throttle (чей планировщик по умолчанию - пул потоков).Только в тот момент, когда вам нужны гарантии синхронизации, введите оператор * On.

Предложение Пола параметризировать вызов Throttle также является хорошим.В случаях, когда вы можете контролировать весь введенный параллелизм, вы можете захотеть это сделать.Тем не менее, во многих случаях вам передается последовательность IObservable, которая плохо себя ведет в отношении требований к синхронизации, что требует использования операторов * On.

5 голосов
/ 07 января 2012

Просто измените строку на:

.Throttle(TimeSpan.FromMilliseconds(33), DispatcherScheduler.Instance)

В любом случае, он более эффективен (хотя 33 мс - очень короткий интервал времени, ударяющий по разрешению таймера)

...