您可能已经在 Rx 代码中使用了调度程序,而没有明确说明要使用的调度程序的类型。这是因为所有处理并发的 Observable 操作符都有多个重载。如果不使用将调度程序作为参数的重载,Rx 将使用最小并发性原则选择一个默认调度程序。这意味着选择引入满足运营商需求的最少并发性的调度器。例如,对于返回具有有限和少量消息的 observable 的运算符,Rx 调用 Immediate。对于返回潜在大或无限数量的消息的操作符,调用 CurrentThread。对于使用定时器的操作符,使用 ThreadPool。
因为 Rx 使用最小并发性调度程序,如果您想为性能目的引入并发性,或者遇到线程相关性问题,则可以选择不同的调度程序。前者的一个例子是,当你不想阻塞一个特定的线程,在这种情况下,你应该使用 ThreadPool。后者的一个示例是,当您想要在 UI 上运行计时器时,在这种情况下,您应该使用 Dispatcher。要指定特定的调度器,可以使用那些接受调度器的运算符重载,例如 Timer(TimeSpan.FromSeconds(10),Scheduler.DispatcherScheduler())。
在以下示例中,源可观察序列以疯狂的速度生成值。 Timer 运算符的默认重载将在 ThreadPool 上放置 OnNext 消息。
- Observable.Timer(Timespan.FromSeconds(0.01))
- .Subscribe(…);
这将在观察者上快速排队。我们可以通过使用 ObserveOn 运算符来改进此代码,这允许您指定要用于将推送通知(OnNext)发送给观察者的上下文。默认情况下,ObserveOn 运算符确保 OnNext 将在当前线程上调用尽可能多的次数。您可以使用其重载并将 OnNext 输出重定向到不同的上下文。此外,您可以使用 SubscribeOn 运算符返回将操作委派给特定调度程序的代理 observable。例如,对于 UI 密集型应用程序,您可以委派所有后台操作在后台运行的调度程序上使用 SubscribeOn 并传递给它一个 ThreadPoolScheduler。为了接收被推出并且访问任何 UI 元素的通知,您可以将 DispatcherScheduler 的实例传递给 ObserveOn 运算符。
以下示例将在当前调度程序上计划任何 OnNext 通知,以便在 UI 线程上发送任何推出的值。这对使用 Rx 的 Silverlight 开发人员特别有利。
- Observable.Timer(Timespan.FromSeconds(0.01))
- .ObserveOn(Scheduler.DispatcherScheduler)
- .Subscribe(…);
而不是使用 ObserveOn 运算符来更改 observable 序列生成消息的执行上下文,我们可以在正确的位置创建并发开始。 当运算符通过提供调度程序参数重载来参数化并发性引入时,传递合适的调度程序将导致使用 ObserveOn 运算符的位置减少。 例如,我们可以通过更改源使用的调度器来解除阻塞观察者并直接订阅 UI 线程,如下面的示例所示。 在这段代码中,通过使用 Timer 重载,它需要一个调度器,并提供 Scheduler.Dispatcher 实例,从这个可观察序列推出的所有值都将来自 UI 线程。
- Observable.Timer(Timespan.FromSeconds(0.01), Scheduler.DispatcherScheduler)
- .Subscribe(…);
您还应该注意,通过使用 ObserveOn 运算符,将为通过原始可观察序列的每个消息计划一个操作。 这可能改变定时信息以及对系统施加额外的压力。 如果你有一个查询,组成在许多不同的执行上下文运行的各种可观察序列,并且在查询中进行过滤,最好在查询中稍后放置 ObserveOn。 这是因为查询可能会过滤掉大量消息,并且将 ObserveOn 运算符放在查询中较早的位置会对将被过滤掉的消息执行额外的工作。 在查询结束时调用 ObserveOn 运算符将产生最小的性能影响。
明确指定调度程序类型的另一个优点是,您可以为性能目的引入并发性,如以下代码所示。
- seq.GroupBy(...)
- .Select(x=>x.ObserveOn(Scheduler.NewThread))
- .Select(x=>expensive(x)) // perform operations that are expensive on resources
来源: http://www.bubuko.com/infodetail-1971278.html