[RxUI] 14 – 调度

[RxUI] 14 – 调度

调度是编写任何使用Reactive Extension程序的核心部分,因为所有操作符都可以被延迟(即在其它线程或UI线程上运行)。调度器允许程序控制上下文代码在其中运行,并很重要的一点是在其它线程上运行代码的库必须能够识别调度器。ReactiveUI提供了两个程序级的调度器,应该用它们替代其它调度器(例如内置的Rx调度器):

  • RxApp.MainThreadScheduler — 此调度器在UI线程上执行。在基于XAML的平台上,等效于Dispatcher.BeginInvoke。
  • RxApp.TaskpoolScheduler — 此调度程序通过TPL任务池执行代码。等效于Task.Run。

要使用这两个内置调度器,需要在Observable链中使用ObserveOn操作符:

this.WhenAnyValue(x => x.MyImportantProperty).ObserveOn(RxApp.MainThreadScheduler).Subscribe(x => ...);

要控制ReactiveControl在哪里运行订阅,可以传入一个调度器。默认情况下,会使用当前线程的调度器,因此,如果从UI线程初始化,就将使用UI线程运行。

MyCommand = ReactiveCommand.Create<Unit, string>(_ => ...do stuff..., outputScheduler: RxApp.
MainThreadScheduler);

可以通过传入调度器来控制ObservableAsPropertyHelper在何处触发INotifyPropertyChanged事件。默认情况下,会使用当前线程的调度器,因此,如果从UI线程初始化,将使用UI线程运行。

public class MyVm : ReactiveObject
{
  private readonly ObservableAsPropertyHelper<bool> _isRunning;

  public MyVm()
  {
    MyCommand = ReactiveCommand.Create<Unit, string>(_ => ...do stuff..., outputScheduler: RxApp.MainThreadScheduler);
    _isRunning = MyCommand.IsExecuting.ToProperty(this, nameof(IsRunning), scheduler: RxApp.MainThreadScheduler);  
  }

  public ReactiveCommand<Unit, string> MyCommand { get; }
  public bool IsRunning => _isRunning.Value;
}

何时关心调度

应该尝试尝试删除所有的并发源,而不是通过RxAPP进行调度。这并非总是可行,但是通过new Thread()Task.Run创建的线程无法在单元测试中进行控制。解决这些问题的最直接方法是将它们替换为Observable.Start

之前
var result = await Task.Run(() => {
    int number = ThisCalculationTakesALongTime();
    return number;
});

Dispatcher.BeginInvoke(new Action(() => DoAThing()));
现在
var result = await Observable.Start(() => {
    int number = ThisCalculationTakesALongTime();
    return number;
}, RxApp.TaskpoolScheduler);

RxApp.MainThreadScheduler.Schedule(() => DoAThing());

如果创建共享组件,则还应考虑允许将调度器指定为可选的构造函数参数。

测试调度器

在默认情况下,在单元测试运行器中,MainThreadScheduler立即运行代码,而不是在(不存在的)UI线程上运行代码。默认情况下,TaskpoolScheduler保持不变。在交叉调度器下运行的最佳方法是使用With方法,该方法最常与TestScheduler一起使用。这将两个调度器替换为指定的调度器:

new TestScheduler().With(sheduler => 
{
    // Code run in this block will have both RxApp.MainThreadScheduler
    // and RxApp.TaskpoolScheduler assigned to the new TestScheduler.
});

原文 https://www.reactiveui.net/docs/handbook/scheduling

发表回复

您的电子邮箱地址不会被公开。