c# - 从同步服务层边界调用异步方法

标签 c# asynchronous async-await c#-5.0

这可能已经在网络上的某个地方得到了回答,但我已经看了很多例子,但我仍然无法弄明白。

我有一个基于同步的服务层边界(例如“ProcessOrder”方法)。在这个方法中,它执行各种功能,其中一些具有异步重载,使用它们很有意义,因为它们包装了 I/O 绑定(bind)函数。

但是,我的困惑有两个方面。根据我的阅读:

  • 异步代码应该“一直异步”
  • 异步标记的方法不应返回 void - 这是事件处理程序和
    的边缘情况 不处理冒泡异常

因此,使用如下示例代码(注意:_publisher 是具有异步发送方法的 Azure QueueClient 的包装器):

public void ProcessOrder()
{
    // other stuff...

    _publisher.PublishAsync(new ItemOrderedEvent()
    {
        MessageId = Guid.NewGuid(),
        IsDurable = true,
    }).Wait();
}

似乎不符合“异步一直向下”的规则,并且由于这种模式在高负载下线程池耗尽,网络上有关于死锁等的警告,但代码如下:

public async void ProcessOrder()
{
    // other stuff...

   await  _publisher.PublishAsync(new ItemOrderedEvent()
    {
        MessageId = Guid.NewGuid(),
        IsDurable = true,
    });
}

打破了“异步标记的方法不应返回 void”的规则,并且不会处理异常,因为据我所知,没有任务上下文可以将它们从异步方法中冒出来。注意:这是一个服务边界——调用代码可能是 UI,以响应 MSMQ 消息、Web 服务调用等,所以我不希望服务调用的“实现”泄漏到更高的地方。在当前上下文中,IMO,这只是一个同步调用是有意义的。

发布者方法定义为:

public async Task PublishAsync(IMessageBusMessage message)
{
    // do azure stuff
    var _queue = QueueClient.CreateFromConnectionString(connectionString, "ItemOrdered");
    await _queue.SendAsync(message);
}

所以我的问题是……您到底是如何在基于同步的架构中使用合法的 I/O 绑定(bind)异步方法的?典型的答案似乎是“你不能”(正如这个 Calling async methods from a synchronous context 所建议的)但是我一定遗漏了一些东西,因为想要卸载 I/O 绑定(bind)工作并让当前线程做一些其他事情似乎是完全合理的在不基于 UI 的上下文中工作。

最佳答案

NB: This is a service boundary - the calling code may be UI, in response to an MSMQ message, a web service call etc. so I do not want "implementation" of the service call to leak higher up. In the current context, IMO, it makes sense for this to be a sync call only.

实际上,你搞错了。 :)

考虑这个方法声明:

public void ProcessOrder();

这绝对是同步的。如果它做任何异步的事情,它就会阻塞,所以它会表现得像同步的。唯一可以将其解释为异步的方式是它采用某种回调或与事件或类似事件配对,在这种情况下,它无疑是异步的。

现在考虑这个方法声明:

public Task ProcessOrderAsync();

这很可能是异步的。但它可能可能是同步的,如果它返回一个已经完成的任务。等待有一个 "fast path" shortcut它用来处理这种情况,实际上将其视为同步。缓存是在实践中使用的一个例子;缓存命中是同步的。

因此,如果您想抽象掉实现的异步性,那么您应该使用异步 方法声明。

注意:Task 返回方法是(可能)异步声明,而 async 是实现细节。

也就是说,there are a variety of ways to "wrap" asynchronous code into a synchronous API ,但它们中的每一个都有缺点,并且它们都不适用于所有情况。最好让您的 API 说出真相:如果任何实现可能是异步的,那么方法声明也应该是异步的。

关于c# - 从同步服务层边界调用异步方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23080362/

相关文章:

javascript - SignalR Client 开始连接时如何设置用户?

c# - 在另一个线程中运行 WPF 控件

asp.net-mvc - 坚持使用 ASP.NET MVC4 中的 Google API YouTube 搜索示例?

ios - swift iOS : Closure will not run in background when Remote Notification received

c# - 通过调用 <asyncmethod>.Result 实现同步方法

javascript - 如何从 Node.js 中的 Promise 和 async/await 函数返回值

c# - 使用共享词典是解决缺少 "extension properties"的好方法吗?

c# - Windows Phone 8 slider 绑定(bind)仅在单击后起作用

c# - Log4net LogicalThreadContext 未按预期工作

c# - 使用 async/await,continuation 什么时候发生?