4

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

4

2 回答 2

6

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

您可以在此处查看一些细微的细节:线程饥饿和排队

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

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

于 2019-08-22T14:22:22.123 回答
4

我的理论是 return Authorized(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. 任务应该在传递给或其他助手await之前进行编辑。Ok
  2. 这引入了GetPresentationByEventAsync,假设您的数据访问代码可以是异步的。

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

使用 Async Await 会避免线程耗尽吗?

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

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

于 2019-08-22T14:38:08.210 回答