使用共享接口跨网络同步异步

Async over sync across network with shared interface

我知道我们通常应该避免异步优于同步,反之亦然。以下是 Stephen Toub 的两篇文章,很好地解释了这一点:

我们使用 WCF 进行跨层通信,并有一个由服务和客户端使用的共享合同。客户端使用 ChannelFactory<TContract> 创建代理和通道。这样做的一大好处是我们不必手动更新我们的 [许多] 服务引用,并且如果接口发生变化,我们可以在双方进行自动编译时检查。然而,这也意味着我们不能保持服务器端接口同步(不是 returning a Task<Result>),也不能让客户端代理是异步的(return Task<Result>由于网络跃点)。

所以我的问题是,是否有真正的 harm/downside 让合同 return 键入 Task<Result> 并在服务器端只执行 return Task.FromResult(SyncCode());?我们在服务器端有效地执行异步优于同步以在客户端启用异步,但网络在技术上已经是异步的了。 Task.FromResult() 不应创建任何额外的线程或引入任何显着的开销。这似乎是规则的合理例外?

换句话说,我可能有一个类似于下面的实现:

public PersonResult GetPerson(int id)
{
    return SyncCode();
}

public Task<PersonResult> GetPersonAsync(int id)
{
    return Task.FromResult(GetPerson(id));
}

我的示例代码不允许激活服务,因为附加 Async 被认为是相同的方法名称。错误是,"Cannot have two operations in the same contract with the same name, methods GetPersonAsync and GetPerson in type ... violate this rule."

根据该错误消息,我在这里找到了更好的解决方案:。您有一个要在服务器端实现的同步接口,并创建一个为客户端添加异步的派生接口。由于 WCF 在通过网络发送消息时忽略了名称中的 Async,因此无论哪种方式,您都在调用相同的方法。

Task.FromResult() shouldn't create any additional threads or introduce any significant overhead. Does this seem like a reasonable exception to the rule?

不,这不是一个合理的例外(如果您有选择的话),因为它会损害 WCF 服务的可伸缩性。在可用的情况下,在服务器端使用自然异步 API 符合您的最大利益。

对于客户端,将 WCF 契约接口方法定义为 PersonResult GetPerson(int id)Task<PersonResult> GetPersonAsync(int id) 并不重要。客户端将以任何一种方式工作,甚至无需重新编译 WCF 代理。更多详情:

  • Different forms of the WCF service contract interface.

WCF 客户端中的异步完全独立于 WCF 服务中的异步。通常,您希望在双方都使用异步,但出于不同的原因:在客户端应用程序中保持 UI 响应,并增加服务器端的吞吐量。更多详情:

  • Calling async methods from a WCF service.