使用RX Throttle时的跨线程异常

Vit*_*lij 5 .net reactive-programming system.reactive c#-4.0

我正进入(状态

无效的跨线程访问.

使用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);
                           });
Run Code Online (Sandbox Code Playgroud)

但如果我省略油门一切正常.

据我所知,Throttle使用线程池,因此OnNext不会发生在UI线程上.但是SubscribeOnDispatcher应该将它封送回UI线程.不应该吗?

小智 12

您对SubscribeOnDispatcher的理解不正确.首先,让我们区分两个*On运算符:

  • SubscribeOn* - 在指定的调度程序上运行(un)订阅逻辑.很少使用,除非你玩Observable.Create等.
  • ObserveOn* - 在指定的调度程序上运行观察者消息(OnNext,OnError,OnCompleted).运行传递给Subscribe的"事件处理程序"时,主要用于UI同步.

为了使您的示例工作,您还应该在查询中进一步使用ObserveOn运算符.我们的建议是在最终的订阅电话面前这样做.在查询中,并发性可以由诸如Throttle(其默认调度程序是线程池)的运算符引入.只有在您需要同步保证时,才会引入*On运算符.

Paul建议参数化Throttle调用也是一个很好的建议.如果您可以控制所引入的所有并发性,您可能希望这样做.但是,在许多情况下,您需要处理一个在同步要求方面不正常的IObservable序列,需要使用*On运算符.


Ana*_*tts 5

只需将行更改为:

.Throttle(TimeSpan.FromMilliseconds(33), DispatcherScheduler.Instance)
Run Code Online (Sandbox Code Playgroud)

无论如何,它都更高效(尽管33ms是一个非常短的时间跨度节流阀,与计时器分辨率相抵触)