【问题标题】:WCF service blocking the UI thread even though CallbackBehavior attribute is defined即使定义了 CallbackBehavior 属性,WCF 服务也会阻止 UI 线程
【发布时间】:2013-12-12 14:13:47
【问题描述】:

我在 .Net 4.0 WPF 应用程序中使用 WCF 服务,并且我观察到对 WCF 服务的调用会阻止 UI 线程上的更新,即使它在服务类上定义了 UseSynchronizationContext = false。

以下代码在包含 Thread.Sleep() 时不会阻止 UI,但是当包含对 api.GetFieldExpressionAssemblies() 的调用时,它会阻止对 UI 的更新。

此代码正在后台线程上执行,并已使用响应式扩展方法 ObserveOn() 和任务池调度程序进行调度。

.ObserveOn(Scheduler.TaskPool)
.Select(x =>
{
    var api = factory.Create();
    using (new Duration())
    {
        //Thread.Sleep(5000);
        //return new Dictionary<string, string[]>();
        return ExtractIntellisense(api.GetFieldExpressionAssemblies().Single());
    }
})

Rx 版本 = 1.0.10621.2,这是 Rx 的旧版本,我知道 issues 使用此版本的 Rx 调度程序将工作调度到任务池,但事实上 Thread.Sleep()不阻塞 UI 线程表明这不是问题。

任何想法为什么会发生这种情况?

【问题讨论】:

  • api.GetFieldExpressionAssemblies() 是什么意思?也许它正在 UI 线程中执行它的代码。你有相关的代码吗?
  • 这是对 WCF 服务的调用,它返回“程序集”的集合
  • 奥卡姆剃刀建议 (1) return ExtractIntellisense(api.GetFieldExpressionAssemblies().Single()) 正在 UI 线程上工作 (2) UI 线程上的某些东西正在等待结果 (3) UI 线程未被阻止这段代码,在处理结果后会发生阻塞。你能提供一些澄清吗?或许还有代码显示如何使用 RX?
  • 您说 “它在服务类上定义了 UseSynchronizationContext = false” - 这仅与客户端代理类上的 CallbackBehavior 相关。你是这个意思吗?如果没有,您如何调用该服务?通过 APM 方法(BeginXXX、EndXXX)、任务样式,还是同步?如果您正在使用回调并且未指定 CallbackBehavior(UseSynchronizationContext=false),则同步上下文将在代理上调用 Open() 的线程上建立,或者在代理上首次调用的线程上建立(如果未显式)打开。
  • 另外,您可能想尝试使用 Spy 方法检查所有线程是否符合预期。 stackoverflow.com/questions/20220755/…

标签: c# wpf multithreading wcf system.reactive


【解决方案1】:

我的通灵调试器说,如果您将此代码包装在 Task.Run 中,它将起作用。 Rx 在这里工作正常,但是 WCF 在您创建 Observable 时捕获同步上下文,这可能是 UI 线程,因为 WCF 是愚蠢的。

【讨论】:

  • Paul 感谢您的洞察力 - 我应该将哪个部分放在 Task.Run 中,选择语句?
  • 整件事——但是,我更建议它来证明正在发生的事情,而不是作为生产解决方案
【解决方案2】:

我已经能够证明问题不在于绑定来自 WCF 的结果,因为即使从 WCF 返回的结果实际上并未从 Rx 链返回,以下代码仍会阻塞 UI。

这表明尝试保罗的建议。

.ObserveOn(SchedulerService.TaskPool)
.Select(x =>
{
   var api = factory.Create();
   using (new Duration())
   {
      var intellisenseDictionary = ExtractIntellisense(api.GetFieldExpressionAssemblies().Single());
      //return intellisenseDictionary;

      return new Dictionary<string, string[]>();
 }

【讨论】:

    【解决方案3】:

    所以像往常一样,答案很简单,有人将 WCF 服务 ConcurrencyMode 更改为 Single,请求以串行方式处理。

    这支持了我所看到的 - 但有一点不同,UI 线程没有被阻塞我仍然可以移动窗口并且它正在被重绘,只是数据没有出现。

    WCF 很烂!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-05
      • 2021-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-07
      • 1970-01-01
      • 2021-03-29
      相关资源
      最近更新 更多