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



我们正在排查.NET Core API端点上的以下性能问题:

  1. 在次要负载下,终结点始终以不到500MS的速度返回。
  2. 当我们从 3 个浏览器到达端点时,每秒一个请求,它会逐渐变慢(在添加第三个浏览器进行调用的一分钟内,响应时间会下降到50,000MS或更糟。
  3. 每个额外的浏览器都会添加 API 使用的线程,例如 40 个线程基础,第二个浏览器命中端点导致 52 个线程,第三个峰值达到 70 个,依此类推。
  4. 加载一个终结点时,整个 API 会缓慢返回(所有终结点(。这是我考虑"线程耗尽"的主要原因,以及第 #3 点。

代码当前如下所示:

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

我的理论是,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是第三方库的一部分,所以我不能轻易测试。想知道这是否看起来像一个可能的问题/解决方案。

是的,异步等待可以减少线程耗尽。简而言之,当您生成的任务多于 ThreadPool 可以处理的任务时,就会出现线程耗尽。

您可以在此处检查一些微妙的指定: 线程不足和排队

您唯一需要记住的是,您永远不应该在任务中阻塞。这意味着使用 async await 调用异步代码(并且永远不要使用 .等待或 。未完成任务的结果(。

如果您使用某些不使用异步等待模式的阻塞代码,则必须在专用线程(而不是任务线程队列(上生成它。

我的理论是返回授权(authDto => 保留一个线程,直到它返回,导致线程耗尽。

是的。您可以通过查看方法的返回值来轻松判断该方法是否同步。IActionResult不是可等待的类型,因此此方法将同步运行。

授权是第三方库的一部分,所以我不能轻易测试。想知道这是否看起来像一个可能的问题/解决方案。

可能。这完全取决于Authorized是否可以处理异步委托。如果可以,那么这样的事情就会起作用:

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

注意:

  1. 任务在传递给Ok或其他帮助者之前应await
  2. 这引入了GetPresentationByEventAsync,假设您的数据访问代码可以异步。

由于使GetPresentationByEvent异步可能需要一些工作,因此值得在尝试此操作之前调查Authorized是否可以采用异步委托。

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

是和不是。异步代码(包括async/await(确实使用较少的线程,因为它避免了阻塞线程。但是,仍然有限制。线程耗尽仍然是可能的,因为异步代码需要一个空闲线程才能完成。使用异步代码,通常可以在遇到可伸缩性问题(如线程耗尽(之前实现一两个数量级的可伸缩性。

有关asyncASP.NET 的更多概念性信息,请参阅此 MSDN 文章。

相关内容

  • 没有找到相关文章

最新更新