RX代码会阻止UI线程?

时间:2018-07-19 05:33:14

标签: c# reactive-programming system.reactive

我正在经历反应式编程(Rx),其有趣的功能之一是订阅和观察不同的线程。但是在这里它以某种方式阻塞了UI线程。从技术上讲,我没有任何返回Task的方法(异步方法),所以在这里我试图用Thread.Sleep模仿一个漫长的过程:

IEnumerable<Item> _search(string searchText)
{
        Thread.Sleep(3000);
        //return result by querying ...
        //...
        return someResult;
}

我有一个像这样的ViewModel类:

public class ViewModel {
   public ViewModel(){
       //this SubscribeOn may not be necessary but I just try it here for sure
       SearchTextStream.SubscribeOn(NewThreadScheduler.Default)
                       .ObserveOn(DispatcherScheduler.Current)
                       .Subscribe(searchText => {
                          var items = _search(searchText);
                 }, ex => {
                    //handle error
            });
   }
   public string SearchText
   {
        get
        {
            return _searchText.FirstAsync().Wait();
        }
        set
        {
            _searchText.OnNext(value);
        }
   }
   ISubject<string> _searchText = new BehaviorSubject<string>("");
   public IObservable<string> SearchTextStream
   {
        get
        {
            return _searchText.AsObservable().DistinctUntilChanged();
        }
   }
}

实际上,在没有使用Thread.Sleep的情况下,我仍然可以看到它阻塞了UI,但不是很明显,因此我只是使用它使它变得更明显。就像我说的,这里的场景是我只有一个普通方法,没有任何任务或异步。这可能是一个长期运行的方法。与RX一起使用时,我不知道应该做些什么才能使其表现得像异步(就像在使用Task.Run时一样)?

如果有问题,我正在测试WPF应用程序。

1 个答案:

答案 0 :(得分:1)

您正在_search(searchText)调度程序上调用DispatcherScheduler.Current-因此,使用Thread.Sleep会阻塞UI。

您确实应该使_search返回可观察的结果。

IObservable<IEnumerable<Item>> _search(string searchText)
{
    Thread.Sleep(3000);
    //return result by querying ...
    //...
    return Observable.Return(new [] { new Item() });
}

现在构造函数应如下所示:

public ViewModel()
{
    SearchTextStream
        .ObserveOn(System.Reactive.Concurrency.Scheduler.Default)
        .SelectMany(searchText => _search(searchText))
        .ObserveOnDispatcher()
        .Subscribe(items =>
        {
            /* do something with `items` */
        }, ex =>
        {
            //handle error
        });
}