简体   繁体   English

使用异步等待是否可以避免线程耗尽?

[英]Does Using Async Await Avoid Thread Exhaustion?

We are troubleshooting the following performance issues on a .NET Core API endpoint: 我们正在对.NET Core API终结点上的以下性能问题进行故障排除:

  1. The endpoint consistently returns in less than 500MS under minor load. 端点在较小负载下始终以不到500MS返回。
  2. When we hit the endpoint from 3 browsers, with one request a second, it gets progressively slower (within a minute of adding a third browser making calls, response times drops to 50,000MS or worse. 当我们从3个浏览器到达端点时,每秒发出一个请求,它逐渐变慢 (在添加第三个浏览器进行呼叫的一分钟内,响应时间下降到50,000MS或更差。
  3. Each additional browser adds threads used by the API , eg 40 threads base, 2nd browser hitting endpoint leads to 52 threads, third spikes to 70, and so on. 每个其他浏览器都会添加API使用的线程 ,例如40个线程基础,第二个浏览器命中端点导致52个线程,第三个峰值达到70个,依此类推。
  4. When one endpoint is loaded, the entire API returns slowly (all endpoints). 加载一个端点后,整个API会缓慢返回(所有端点)。 This is my main reason for thinking "thread exhaustion", along with point #3. 这是我思考“线程耗尽”的主要原因,以及第3点。

The code currently looks like this: 当前代码如下:

    public IActionResult GetPresentationByEvent(int eventid)
    {
      return Authorized(authDto =>
      {
        var eventList = _eventService.GetPresentationByEvent(eventid);
        return Ok(eventList)
      })
    }

My theory is that return Authorized(authDto => holds a thread until it returns, leading to thread exhaustion. 我的理论是return Authorized(authDto =>保持线程直到返回,导致线程耗尽。

    public async Task<IActionResult> GetPresentationByEvent(int eventid)
    {
      return Authorized(async authDto =>
      {
        Task<List<whatever>> eventList = _eventService.GetPresentationByEvent(eventid);
        return Ok(eventList)
      }
    }

Authorized is part of a third-party library, so I can't test this easily. Authorized是第三方库的一部分,因此我无法轻松对其进行测试。 Would like to know if this looks like a likely problem/solution. 想知道这是否是一个可能的问题/解决方案。

Yes async await can reduce thread exhaustion. 是的,异步等待可以减少线程耗尽。 In a few words thread exhaustion arise when you generate more tasks than your ThreadPool can handle. 简而言之,当您生成更多任务而不是ThreadPool可以处理时,就会出现线程耗尽。

There are subtle specifities that you can check here : Thread starvation and queuing 您可以在此处检查细微的特殊性: 线程饥饿和排队

The only thing that you have to keep in mind on your side is that you should never block inside a task. 您唯一需要牢记的是,您永远都不应阻塞任务内部。 This implies calling asynchronous code with async await (and never using .Wait or .Result on a non finished task). 这意味着在异步等待状态下调用异步代码(并且不要在未完成的任务上使用.Wait或.Result)。

If you use some blocking code wich is not using the async await pattern you have to spawn it on a dedicated thread (not the task thread queue). 如果使用的阻塞代码未使用异步等待模式,则必须在专用线程(而不是任务线程队列)上生成它。

My theory is that return Authorized(authDto => holds a thread until it returns, leading to thread exhaustion. 我的理论是return Authorized(authDto =>保持线程直到返回,导致线程耗尽。

Yes. 是。 You can easily tell whether a method is synchronous by looking at its return value. 通过查看方法的返回值,可以轻松判断该方法是否同步。 IActionResult is not an awaitable type, so this method will run synchronously. IActionResult不是等待的类型,因此此方法将同步运行。

Authorized is part of a third-party library, so I can't test this easily. 授权是第三方库的一部分,因此我无法轻松对其进行测试。 Would like to know if this looks like a likely problem/solution. 想知道这是否是一个可能的问题/解决方案。

Possibly. 可能吧。 It all depends on whether Authorized can handle asynchronous delegates. 这完全取决于Authorized是否可以处理异步委托。 If it can, then something like this would work: 如果可以的话,这样的事情会起作用:

public async Task<IActionResult> GetPresentationByEvent(int eventid)
{
  return Authorized(async authDto =>
  {
    Task<List<whatever>> eventList = _eventService.GetPresentationByEventAsync(eventid);
    return Ok(await eventList);
  });
}

Note: 注意:

  1. Tasks should be await ed before being passed to Ok or other helpers. 在将任务传递给Ok或其他帮助者之前,应await任务。
  2. This introduces GetPresentationByEventAsync , assuming that your data-accessing code can be made asynchronous. 这引入了GetPresentationByEventAsync ,假设可以使您的数据访问代码异步。

Since making GetPresentationByEvent asynchronous may take some work, it's worthwhile to investigate whether Authorized can take asynchronous delegates before attempting this. 由于使GetPresentationByEvent异步可能需要一些工作,因此值得尝试一下Authorized是否可以接受异步委托。

Does Using Async Await Avoid Thread Exhaustion? 使用异步等待是否可以避免线程耗尽?

Yes and no. 是的,没有。 Asynchronous code (including async / await ) does use fewer threads, since it avoids blocking threads. 异步代码(包括async / await )确实使用较少的线程,因为它避免了阻塞线程。 However, there is still a limit. 但是,仍然有一个限制。 Thread exhaustion is still possible since asynchronous code needs a free thread to complete . 由于异步代码需要一个空闲线程来完成,因此线程耗尽仍然是可能的。 With asynchronous code, usually you can achieve an order of magnitude or two greater scalability before you run into scalability problems like thread exhaustion. 使用异步代码,通常在遇到诸如线程耗尽之类的可伸缩性问题之前,可以实现一个数量级或两个以上的可伸缩性。

For more conceptual information on async ASP.NET, see this MSDN article . 有关async ASP.NET的更多概念性信息,请参见此MSDN文章

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

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