这个异步/等待代码导致潜在的死锁?

Syl*_*voo 0 .net c# multithreading async-await azureservicebus

我有以下课程:

public abstract class ServiceBusQueueService : IServiceBusQueueService
{
    private readonly string _sbConnect;

    protected ServiceBusQueueService(string sbConnect)
    {
        _sbConnect = sbConnect;
    }

    public async Task EnqueueMessage(IntegrationEvent message)
    {
        var topicClient = new TopicClient(_sbConnect, message.Topic, RetryPolicy.Default);
        await topicClient.SendAsync(message.ToServiceBusMessage());
    }
}
Run Code Online (Sandbox Code Playgroud)

正在使用的是这样的:

public ulong CreateBooking()
{
     // Other code omitted for brevity 
     ulong bookingId = 12345; // Pretend this id is generated sequentially on each call

      _bookingServiceBusQueueService.EnqueueMessage(new BookingCreatedIntegrationEvent
      {
            BookingId = bookingId
      }).GetAwaiter().GetResult();

      return bookingId;
}
Run Code Online (Sandbox Code Playgroud)

EnqueueMessage从我的CreateBooking方法调用该方法时,该程序挂起并且在点击该行之后不再继续await topicClient.SendAsync(message.ToServiceBusMessage());

现在代码工作,当我将调用更改为my EnqueueMessage方法时,我的消息成功推送到Service总线,如下所示:

Task.Run(() => _bookingServiceBusQueueService.EnqueueMessage(new BookingCreatedIntegrationEvent
        {
            BookingId = bookingId
        })).Wait();
Run Code Online (Sandbox Code Playgroud)

我对使用async/await不是很熟悉,经过一些研究后听起来像是导致死锁,这是正确的吗?为什么更改方法调用会Task.Run(() => SomeAsyncMethod()).Wait();导致它停止挂起并按预期工作?

Eri*_*ert 10

假设我给你以下工作流程:

  1. 写一个说"割草坪"并把它放在冰箱上的便条.
  2. 在完成说明中提到的任务之前什么都不做.
  3. 做一个三明治
  4. 把任务写在冰箱上的笔记上.

如果您遵循该工作流程,您将进入步骤(2),然后永远不执行任何操作,因为您正在等待步骤(1)的任务完成,直到步骤(4)才开始.

你在软件中有效地编码相同的工作流程,所以难怪你永远等待.

那么为什么要添加Run"修复"呢?这是另一个工作流程:

  1. 写一个说"割草坪"的笔记,雇一个工人,然后把这个笔记交给工人
  2. 在说明中提到的任务完成之前,绝对不要做任何事情
  3. 做一个三明治

现在你不要永远等待.你等待工人修剪你的草坪,这只是低效和浪费.你可以在等待的时候做其他的工作,就像做三明治一样.或者你可以自己修剪草坪,而不是以雇用工人为代价.

这就是为什么你永远不会同步等待异步操作.只有两种可能性:如果将来进行异步操作,你会永远等待,这显然已经被打破了.如果你不是,那么你在做工作时就会浪费时间睡觉,这显然是浪费.

使用设计使用的异步:异步.