【问题标题】:Why is this Observable blocking the WPF GUI thread (C#)?为什么这个 Observable 会阻塞 WPF GUI 线程(C#)?
【发布时间】:2016-01-22 23:04:46
【问题描述】:

给定:一个扩展方法,采用 Selenium IWebdriver 实例并返回一个 IObservable

     public static IObservable<ObservableCollection<WebElementWrapper>> 
      GetAllElementsAsObservable(this IWebDriver wd)
      {
        return Observable.Create<ObservableCollection<WebElementWrapper>>(
             (IObserver<ObservableCollection<WebElementWrapper>> observer) =>
             {                     
                     var eles = wd.FindElements(By.CssSelector("*"));
                     var list = eles.ToWebElementObservableCollection();
                     observer.OnNext(list);
                     observer.OnCompleted();                     

                 return Disposable.Create(() => { });
             });
      }

以及调用上述方法的代码(在GUI线程上运行)...

                //GUI Will Freeze on this call until OnCompleted is called
                cd.GetAllElementsAsObservable().Subscribe((WEWList) =>
                {
                    WebElementCollection = WEWList;
                    SetNavigationItems();
                });

在调用 OnCompleted 之前,谁能帮我确定 GUI 线程阻塞的根本原因。如果我在第一种方法中使用 Task.Run,​​我可以停止阻塞,但是我必须将集合编组回 GUI 线程。

这个阻塞是因为 GUI 线程启动了 Observable 用来提取元素的 Webdriver 吗?

或者这是因为在 GUI 线程启动时创建的静态方法?

【问题讨论】:

  • 如果你这样做了 - Disposable.Create(() =&gt; { }) - 你做错了什么。使用Observable.Create 的方式是一种阻塞操作。 .Create 中的代码是订阅的一部分,但您在订阅期间运行观察者完成,这就是它阻塞的原因。

标签: c# wpf selenium system.reactive


【解决方案1】:

如果你这样做了 - Disposable.Create(() =&gt; { }) - 你做错了什么。使用Observable.Create 的方式是阻塞操作。 .Create 中的代码是订阅的一部分,但您在订阅期间运行观察者以完成,这就是它阻塞的原因。

尝试做这样的事情:

public static IObservable<ObservableCollection<WebElementWrapper>>
    GetAllElementsAsObservable(this IWebDriver wd)
{
    return Observable.Create<ObservableCollection<WebElementWrapper>>(observer =>
        Observable
            .Start(() =>
                wd
                    .FindElements(By.CssSelector("*"))
                    .ToWebElementObservableCollection())
            .Subscribe(observer));
}

【讨论】:

  • Observable.Defer(() =&gt; wd.FindElements(By.CssSelector("*")).ToWebElementObservableCollection()) 会不会更简单?
  • @Gluck - 不,因为.ToWebElementObservableCollection() 不返回可观察值。
  • 对,然后将使用额外的 Obs.Return。我总是试图避免中间订阅而感到内疚。谢谢!
【解决方案2】:

对于 WPF,我也发现这两种方法可以工作..

SomeObservable
.SubscribeOn(Scheduler.Default)
.ObserveOn(Scheduler.CurrentThread)
.Subscribe(item => { //do something on gui thread here });

我不关心方法名称 SubscribeOn,但我是这样看的……我希望 observable 可以订阅某个调度程序。 (我认为更好的名字应该是“SheduleOn”)。

ObserveOn 方法名称是有意义的。但请注意“Scheduler.Dispatcher”内置属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-14
    • 1970-01-01
    • 2014-05-24
    • 2021-08-29
    • 1970-01-01
    • 2015-04-27
    • 1970-01-01
    相关资源
    最近更新 更多