.Net Core Web Api的异步性是否重要?

6

我一直在使用async关键字编写我的Web Api控制器方法,并一路使用async。最近,我尝试将一个方法变成同步方法,以查看它对性能的影响,但惊讶地发现它对任何其他http请求都没有阻塞影响。

举个例子-

[Route("Foo")]
class FooController {
  [HttpGet("Hello")]
  public string GetHello()
  {
    Thread.Sleep(100000); // 100 seconds
    return "Hello";
  }

  [HttpGet("Goodbye")]
  public string GetGoodbye()
  {
    return "Goodbye";
  }
}

我可以运行 GET => /Foo/Hello,然后跟随任意数量的 GET => /Foo/Goodbye,并且对于 Goodbye 端点的请求不会阻塞。最初我认为必须将 Hello 方法设置为异步方法,以便对 Goodbye 端点的请求能够立即返回。但是,将此方法设置为同步/异步都没有影响!非常困惑。Web Api 应用程序是否不需要使用异步?为什么建议使用异步?

ASP.Net Core 使用多个线程。 - SLaks
可能是ASP.NET MVC中何时使用异步控制器?的重复问题。 - Kirk Larkin
建议在大规模运行时使用。小规模测试无法揭示当您的ThreadPool线程用尽、Web服务器队列已满并且请求被拒绝时出现的问题。明智地使用“async”意味着您可能只需使用少量线程即可为数千个并发客户提供服务。现在尝试对在服务器上“block”的请求执行相同操作... - spender
1个回答

16
这并不是那么简单。有一种称为“线程池”的东西。每个应用程序请求都会被分配到一个来自线程池的单独线程中。这就是为什么一个请求不会阻塞其他请求的第一个原因。
现在,当您的流量很低时,您没有达到线程池中的线程数限制,一切都很好。但是...
假设您的请求平均需要1秒,并且您的线程池大小为100,那么您将在第101个请求处开始体验到限制。由于它没有可以分配的线程池,因此必须等待第100个请求完成并释放线程返回线程池,然后才能进行处理。
现在,根据您的请求所做的工作,异步可能会有所帮助(但也可能会引起问题,因此不要盲目使用):
1. 如果您的请求执行I/O操作(网络调用、文件系统、数据库异步等),则这些操作将在I/O线程上执行。它们不来自线程池。因此,想象一下一个请求进来并发出一个网络调用或文件读取,耗时0.93秒。实际上,如果您不使用异步,您的线程池线程在0.93秒内无法使用,并且只会坐在那里等待IO线程完成。在这种情况下,“异步”非常有用,因为一旦它命中使用IO线程的操作和“await”关键字,它就会立即释放线程池中的线程,以便可以处理下一个请求。完成IO操作后,它将从线程池获取线程以提供响应。
2. 如果您的请求不使用任何I/O操作,但是强制其使用异步(有方法可以实现),那么您将只交换一个线程池线程(最初用于接收请求)来运行另一个线程池线程(用于运行操作)。在这种情况下,您只会创建额外开销并且性能下降。
但无论如何,我感觉这与您的问题没有直接关系。在以上两种情况中,您的方法将在2个独立的请求中运行,并且与 async/await 几乎没有关系,而是与处理请求的服务器环境无关。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接