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

C# 使用异步等待是否可以避免线程耗尽?,c#,multithreading,asp.net-core-2.1,non-exhaustive-patterns,C#,Multithreading,Asp.net Core 2.1,Non Exhaustive Patterns,我们正在对.NET Core API端点上的以下性能问题进行故障排除: 在较小负载下,端点始终在小于500MS的时间内返回 当我们从3个浏览器点击端点时,每秒一个请求,会逐渐变慢(在添加第三个浏览器进行调用的一分钟内,响应时间会下降到50000ms,甚至更糟 每个附加浏览器都会添加API使用的线程,例如,基本线程数为40个,第二个浏览器命中端点会导致52个线程,第三个峰值会导致70个线程,依此类推 当加载一个端点时,整个API都会缓慢返回(所有端点)。这是我考虑“线程耗尽”以及第3点的主要原因

我们正在对
.NET Core API
端点上的以下性能问题进行故障排除:

  • 在较小负载下,端点始终在小于
    500MS的时间内返回
  • 当我们从3个浏览器点击端点时,每秒一个请求,会逐渐变慢(在添加第三个浏览器进行调用的一分钟内,响应时间会下降到
    50000ms
    ,甚至更糟
  • 每个附加浏览器都会添加API使用的线程,例如,基本线程数为40个,第二个浏览器命中端点会导致52个线程,第三个峰值会导致70个线程,依此类推
  • 当加载一个端点时,整个API都会缓慢返回(所有端点)。这是我考虑“线程耗尽”以及第3点的主要原因
  • 当前代码如下所示:

        public IActionResult GetPresentationByEvent(int eventid)
        {
          return Authorized(authDto =>
          {
            var eventList = _eventService.GetPresentationByEvent(eventid);
            return Ok(eventList)
          })
        }
    
    我的理论是
    returnauthorized(authDto=>
    会一直保持线程直到它返回,从而导致线程耗尽

        public async Task<IActionResult> GetPresentationByEvent(int eventid)
        {
          return Authorized(async authDto =>
          {
            Task<List<whatever>> eventList = _eventService.GetPresentationByEvent(eventid);
            return Ok(eventList)
          }
        }
    
    公共异步任务GetPresentationByEvent(int-eventid) { 返回已授权(异步身份验证=> { 任务eventList=\u eventService.GetPresentationByEvent(eventid); 返回Ok(事件列表) } }

    Authorized
    是第三方库的一部分,因此我无法轻松测试。我想知道这是否是一个可能的问题/解决方案。

    是的,异步等待可以减少线程耗尽。简单地说,当生成的任务超过线程池的处理能力时,线程耗尽就会出现

    您可以在此处查看一些细微的规范:

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


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

    是的,异步等待可以减少线程耗尽。简单地说,当生成的任务超过线程池所能处理的数量时,就会出现线程耗尽

    您可以在此处查看一些细微的规范:

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

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

    我的理论是,return Authorized(authDto=>会一直保存线程,直到它返回,从而导致线程耗尽

        public async Task<IActionResult> GetPresentationByEvent(int eventid)
        {
          return Authorized(async authDto =>
          {
            Task<List<whatever>> eventList = _eventService.GetPresentationByEvent(eventid);
            return Ok(eventList)
          }
        }
    
    是的。通过查看方法的返回值,可以很容易地判断方法是否同步。
    IActionResult
    不是可等待的类型,因此此方法将同步运行

    授权是第三方库的一部分,因此我无法轻松测试。想知道这是否可能是一个问题/解决方案

    可能。这完全取决于
    授权的
    是否可以处理异步委托。如果可以,那么类似的操作将起作用:

    public async Task<IActionResult> GetPresentationByEvent(int eventid)
    {
      return Authorized(async authDto =>
      {
        Task<List<whatever>> eventList = _eventService.GetPresentationByEventAsync(eventid);
        return Ok(await eventList);
      });
    }
    
    公共异步任务GetPresentationByEvent(int-eventid) { 返回已授权(异步身份验证=> { 任务eventList=\u eventService.GetPresentationByEventAsync(eventid); 返回Ok(等待事件列表); }); }
    注:

  • 任务在传递给
    Ok
    或其他助手之前,应等待
  • 这引入了
    GetPresentationByEventAsync
    ,假设您的数据访问代码可以是异步的
  • 由于使
    GetPresentationByEvent
    异步可能需要一些工作,因此在尝试此操作之前,有必要研究
    Authorized
    是否可以接受异步委托

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

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

        public async Task<IActionResult> GetPresentationByEvent(int eventid)
        {
          return Authorized(async authDto =>
          {
            Task<List<whatever>> eventList = _eventService.GetPresentationByEvent(eventid);
            return Ok(eventList)
          }
        }
    
    有关
    async
    ASP.NET的更多概念信息,请参阅

    我的理论是,return Authorized(authDto=>会一直保存线程,直到它返回,从而导致线程耗尽

        public async Task<IActionResult> GetPresentationByEvent(int eventid)
        {
          return Authorized(async authDto =>
          {
            Task<List<whatever>> eventList = _eventService.GetPresentationByEvent(eventid);
            return Ok(eventList)
          }
        }
    
    是的。通过查看方法的返回值,可以很容易地判断方法是否同步。
    IActionResult
    不是可等待的类型,因此此方法将同步运行

    授权是第三方库的一部分,因此我无法轻松测试。想知道这是否可能是一个问题/解决方案

    可能。这完全取决于
    授权的
    是否可以处理异步委托。如果可以,那么类似的操作将起作用:

    public async Task<IActionResult> GetPresentationByEvent(int eventid)
    {
      return Authorized(async authDto =>
      {
        Task<List<whatever>> eventList = _eventService.GetPresentationByEventAsync(eventid);
        return Ok(await eventList);
      });
    }
    
    公共异步任务GetPresentationByEvent(int-eventid) { 返回已授权(异步身份验证=> { 任务eventList=\u eventService.GetPresentationByEventAsync(eventid); 返回Ok(等待事件列表); }); }
    注:

  • 任务在传递给
    Ok
    或其他助手之前,应等待
  • 这引入了
    GetPresentationByEventAsync
    ,假设您的数据访问代码可以是异步的
  • 由于使
    GetPresentationByEvent
    异步可能需要一些工作,因此在尝试此操作之前,有必要研究
    Authorized
    是否可以接受异步委托

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

    是和否。异步代码(包括
    async
    /
    await
    )使用更少的线程,因为它可以避免阻塞线程。但是,仍然有一个限制。由于