简体   繁体   English

在非异步操作中调用异步方法时出现死锁

[英]Deadlock when calling an async method inside a non async action

We have a web application which consists of a Web API consumed by our UI.我们有一个 web 应用程序,它由我们的 UI 使用的 Web API 组成。 The web application is installed on different servers (tests before installing it by our clients). web 应用程序安装在不同的服务器上(在我们的客户安装之前进行测试)。

On one server, we get a deadlock by the following endpoint:在一台服务器上,我们通过以下端点获得了死锁:

[HttpGet, Route(Order = 1)]
public IHttpActionResult GetUserDetails(long userKey)
{
    var userService = ResolveService<IUserService>();
    var nameService =  ResolveService<INameService >();

    LoggInfo("Start userService.Get()"); //logged in logs
    var result = userService.Get(userKey);
    this.LoggInfo($"End userService.Get() with id = "{result.Id}); // logged in logs

    try
    {
      LoggInfo($"Start nameService.Get()"); // logged in logs
      result.Name =  nameService.Get(result.Namekey).Result?.Name;
      LoggInfo($"End nameService.Get()"); // not logged in logs
    }
   catch(Exception ex)
   {
     LogError("An error occured in NameService"); // not logged in logs
   }

    return Ok(result);
}

nameService.Get(id) is an async method: nameService.Get(id)是一个async方法:

public async Task<NameDTO> GetAsync(long key)
{
    LogInfo("start NameService.Get()"); // not logged in logs
    var query = GetQuery();
    var name = await query.Select(MapName())
                          .FirstOrDefaultAsync(n => n.Key == key);

    return name;
}

When I remove the async signature everything is working as expected, according to this article it is normal to have a deadlock.当我删除异步签名时,一切都按预期工作,根据这篇文章,出现死锁是正常的。

Could you please explain me why this works in the other servers?你能解释一下为什么这在其他服务器上有效吗?

Thanks in advance for your help在此先感谢您的帮助

Could you please explain me why this works in the other servers?你能解释一下为什么这在其他服务器上有效吗?

In order for the deadlock to occur, there are three necessary parts:为了使死锁发生,有三个必要的部分:

  1. A one-thread-at-a-time context, which all servers would have (the pre-Core ASP.NET context).所有服务器都将具有的一次一个线程的上下文(Core ASP.NET 之前的上下文)。
  2. An await (without ConfigureAwait(false) ) that acts asynchronously .异步操作的await (没有ConfigureAwait(false) )。
  3. Code elsewhere that blocks a thread inside that context, waiting for the async method to finish.其他地方的代码会阻塞该上下文中的线程,等待async方法完成。 All servers also have this.所有服务器也有这个。

Most likely, the difference in behavior is due to the second part: an await that acts asynchronously.最有可能的是,行为上的差异是由于第二部分:异步操作的await await first examines its awaitable (eg, the Task passed to it), and if that awaitable is complete, then it continues executing the async method synchronously . await首先检查它的 awaitable(例如,传递给它的Task ),如果该 awaitable 完成,那么它会继续同步执行async方法

Specifically, this would happen if the Task<NameDTO> returned from GetAsync completed before the calling code hit the .Result .具体来说,如果从GetAsync返回的Task<NameDTO>在调用代码命中.Result之前完成,就会发生这种情况。 This would have to be extremely fast, but it's possible depending on caching, how fast your network hop is, how much the code is slowed down by load/neighbors/anti-virus, etc.这必须非常快,但这可能取决于缓存、网络跃点的速度、加载/邻居/防病毒等代码减慢了多少。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM