我正在经历反应式编程(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
应用程序。
答案 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
});
}