C# Rx节流阀(…).ObserveOn(调度程序)和节流阀(…,调度程序)之间的差异
我有以下代码:C# Rx节流阀(…).ObserveOn(调度程序)和节流阀(…,调度程序)之间的差异,c#,system.reactive,reactiveui,C#,System.reactive,Reactiveui,我有以下代码: IDisposable subscription = myObservable.Throttle(TimeSpan.FromMilliseconds(50), RxApp.MainThreadScheduler) .Subscribe(_ => UpdateUi()); 正如预期的那样,UpdateUi()将始终在主线程上执行。当我将代码更改为 IDisposable subscription
IDisposable subscription = myObservable.Throttle(TimeSpan.FromMilliseconds(50), RxApp.MainThreadScheduler)
.Subscribe(_ => UpdateUi());
正如预期的那样,UpdateUi()
将始终在主线程上执行。当我将代码更改为
IDisposable subscription = myObservable.Throttle(TimeSpan.FromMilliseconds(50))
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(_ => UpdateUi());
UpdateUI()
将在后台线程中执行
为什么
Throttle(…).ObserveOn(scheduler)
等同于Throttle(…,scheduler)
?在您给出的代码的两个示例中,UpdateUi
将始终在RxApp.MainThreadScheduler
指定的调度器上调用。我可以肯定地说,因为ObserveOn
是一个decorator,它确保订阅者的OnNext
处理程序在指定的调度程序上被调用。有关深入分析,请参阅
也就是说,这有点令人费解。RxApp.MainThreadScheduler
未引用正确的调度程序调度程序,或者UpdateUi
正在从调度程序线程过渡。前者并非史无前例——看看其他人在哪里遇到了这种情况。我不知道那件事是怎么回事。也许@PaulBetts可以参与进来,或者你可以在会议上提出一个问题。无论是什么情况,我都会仔细检查您的假设,因为我希望这是一个经过良好测试的领域。你有完整的复印件吗
关于您的具体问题,Throttle(…).ObserveOn(scheduler)
和Throttle(…,scheduler)
之间的区别如下:
在第一种情况下,如果指定的Throttle
没有调度程序,它将使用默认的平台调度程序引入运行其计时器所需的并发性-在WPF上,这将使用线程池线程。因此,所有限制都将在后台线程上完成,并且由于以下原因,仅将释放的事件传递给指定调度程序上的订阅者
如果Throttle
指定了一个调度器,则在该调度器上执行节流-抑制的事件和释放的事件都将在该调度器上进行管理,订阅服务器也将在该调度器上调用
因此,无论哪种方式,都将在RxApp.MainThreadScheduler
上调用UpdateUi
在大多数情况下,您最好在调度程序上限制ui事件,因为在后台线程上运行单独的计时器并支付上下文切换费用(如果只有一小部分事件将通过限制)通常成本更高
因此,为了检查您是否在
RxApp.MainThreadScheduler
中遇到问题,我将尝试通过另一种方法显式指定调度器或SynchronizationContext
。如何做到这一点取决于您所在的平台-ObserveOnDispatcher()
有望可用,或者使用合适的ObserveOn
重载。如果导入了正确的Rx
库,则可以选择控件、同步上下文和调度程序。经过一些调查,我认为这是因为运行时使用的Rx版本与我预期的不同(我为第三方应用程序开发了一个插件)
我不知道为什么,但似乎默认的RxApp.MainThreadScheduler
无法正确初始化。默认实例是waitforDispatchersScheduler
()。此类中的所有函数都依赖于attemptoCreateScheduler
:
IScheduler attemptToCreateScheduler()
{
if (_innerScheduler != null) return _innerScheduler;
try {
_innerScheduler = _schedulerFactory();
return _innerScheduler;
} catch (Exception) {
// NB: Dispatcher's not ready yet. Keep using CurrentThread
return CurrentThreadScheduler.Instance;
}
}
在我的例子中,似乎发生了\u schedulerFactory()
抛出,导致返回CurrentThreadScheduler.Instance
通过手动将
RxApp.MainThreadScheduler
初始化为新的SynchronizationContextScheduler(SynchronizationContext.Current)
行为符合预期。谢谢,我的MainThreadScheduler
似乎有问题(请参阅)