【问题标题】:WCF AsyncPattern + Task<T>.Factory.FromAsync = ContextSwitchDeadlockWCF AsyncPattern + Task<T>.Factory.FromAsync = ContextSwitchDeadlock
【发布时间】:2013-02-14 23:49:28
【问题描述】:

我正在尝试通过使用 Task.Factory.FromAsync 将调用包装到客户端的任务中来简化对 WCF 异步操作的调用。但是当我 Start() 包装的任务时,对 Start() 的调用会阻塞客户端,直到调试器报告 ContextSwitchDeadlock。但是,服务器端操作被正确调用。我错过了什么?

WCF 合同:

[ServiceContract(Namespace = "urn:test/test")]
public interface ITestContract
{
    [OperationContract(AsyncPattern=true)]
    IAsyncResult BeginGetResult(AsyncCallback callback, object state);

    int EndGetResult(IAsyncResult result);
}

客户端代码:

var task = Task<int>.Factory.FromAsync(
    (callback, state) => service.BeginGetResult(callback, state),
    (result) => service.EndGetResult(result)
);
task.Start(); // blocks until ContextSwitchDeadlock gets reported

编辑:为了完整起见:不,我不能使用 .NET 4.5 async / await 模式,因为 .NET 4.0(即 Windows XP 和 Server 2003 支持)是我项目的硬性要求。

编辑2:

无论如何都不需要调用Start()。真正的问题是 BeginGetResult 在我调用 Start()Wait()Result 之前不会在服务器端被调用 - 这与同步调用相同。

我发现,这与任务完全无关。如果我执行以下操作,我会得到相同的结果:

var asyncResult = service.BeginGetResult(null, null); // BeginGetResult NOT invoked on server side!
asyncResult.AsyncWaitHandle.WaitOne(); // Now BeginGetResult actually gets invoked

EDIT3:

原来这只是我的一个误会。我预计在客户端调用BeginGetResult立即在服务器端调用相应的BeginGetResult,即客户端的BeginGetResult 会阻塞,直到服务器实际收到请求,但情况似乎并非如此。显然请求是在后台线程中发送的,因此客户端和服务器端对BeginGetResult 的调用之间可能存在延迟。我想这种行为是意料之中的,所以一切都很好:-)。

【问题讨论】:

  • 您可以使用Microsoft.Bcl.Async 库(当前为候选发布版)将async/await 支持添加到.NET 4.0 项目。
  • 谢谢,看起来很有趣!不过,我不确定我是否想要在生产代码中使用 Beta 版。
  • 我明白了。 FWIW,async 即使在 CTP 阶段也非常成熟(并且有据可查);这是我在生产中使用的唯一一款预发布的 MS 软件。
  • 我认为您的编辑没有多大意义。 WaitOne() 不可能导致调用实际开始。

标签: c# .net wcf task-parallel-library


【解决方案1】:

您无需在由FromAsync 创建的Task 上调用StartStart 仅适用于有代码的任务,FromAsync 任务没有任何代码。

【讨论】:

  • 对 - 但很尴尬,除非我调用 task.Start()、task.Wait() 或 task.Result,否则服务器端似乎什么都没有发生。
  • 如果您不使用async,那么您确实需要使用WaitResult 或任务延续。如果您的客户端刚刚退出(快速),那么服务器可能看不到调用。
  • 问题是BeginGetResult 在我调用WaitResult 之前永远不会被调用——这相当于同步调用。
  • 绝对应该在FromAsync处调用。您使用的是默认的 VS 客户端代理吗?
  • 我使用的是共享程序集而不是生成的客户端代理。我使用ChannelFactory&lt;ITestContract&gt; 以编程方式创建代理。
猜你喜欢
  • 2011-01-11
  • 2018-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-12
  • 1970-01-01
相关资源
最近更新 更多