异步优于同步

本文关键字:同步 于同步 异步 | 更新日期: 2023-09-27 18:17:28

我很清楚async over sync是不推荐的。原因是有道理的。

在设置Web API控制器时,我使用和不使用async over sync进行了测试。我设置了一个表,其中包含来自服务的数据和一个按钮,该按钮将根据对服务的单个请求同时更新每个项。令我惊讶的是,没有同步的设置似乎一次可以处理5个批次;async over sync快速且单独地完成了更新:整个批次的完成时间比一个批次的时间多一点。

总的来说,对于Web API控制器:
  • async over sync似乎并行运行所有请求。
  • 正常代码一次最多并行运行5个请求。

考虑到重复的问题和集体文献,我关于使用异步而不是同步来提高性能的结论肯定是有缺陷的。你能解释一下我看到的行为吗?我怀疑答案在于我如何设置本地系统,但我希望那些比我更了解整个领域的人。


"Async over sync"应该是这样的:

public async Task SyncAsync()
{
    return new Task(() => Thread.Sleep(2000));
}

根据来源:

这是毫无意义的,因为你只是将工作从一个ThreadPool线程卸载到另一个线程。

所以我不妨这样写:

public void Sync()
{
    Thread.Sleep(2000);
}

异步优于同步

更新1 你试图说异步并行执行所有请求,但在这种情况下,它会将工作转移到线程池到线程。

  1. 我也在下面解释过,但要明白,你所有的请求都是关于一些API调用或一些I/O调用,在这种情况下,你服务更多的请求,但在同步的情况下,你只有服务器5请求,因为当前线程是块。

在上面我假设线程池的容量为5。

所以当6个请求来了,它将等待在同步的情况下。在异步的情况下,I/O线程池中的所有5个请求都有空闲线程来处理服务器6的请求。这样可以提高应用程序的吞吐量。

还必须确保Task不是线程。任务和线程是不同的。


我在这里用的是一般的,是我在开发过程中测量的最好的。

  1. Async/Await不是提高性能的灵丹妙药。你必须正确地实现它。当执行的任务是基于I/O时,应该使用Async/Await,比如一些数据库调用、Web服务调用或文件系统调用。在这种情况下,它提供了好处,因为I/O操作不需要线程,它不必要地阻塞一个线程。

  2. 如果你在异步/等待中执行CPU密集型任务,那么它不会给你带来性能优势。

  3. 您还必须在各种负载下测试您的应用程序。就像如果你已经托管了你的应用程序IIS和本地你正在测试调试,那么总是有更少的资源消耗,然后你觉得同步是好的,因为他们得到了自由的资源,但当你增加负载(像许多用户在同一时间),然后它创建瓶颈在同步,好像它不会找到自由的线程和请求不会服务,即使在IIS线程内等待I/O完成。

https://msdn.microsoft.com/en-us/magazine/hh456402.aspx

https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

我从您与dotnetstep的讨论中看到,您正试图将MVC应用程序放在一起,但我认为我不需要看到这一点来回答您的问题。Dotnetstep的回答是正确的,但我想详细说明你在评论中提出的一些其他问题。

我想知道线程池5是从哪里来的

这只是dotnetstep选择的任意数字。这个数字将来自web的processModel>maxWorkerThreads部分。配置文件。这是ASP中并发执行请求的数量。. NET可以处理的。这个数字鼓励开发人员尽量减少请求的执行时间。例如,如果这个数字是5,那么ASP。NET可以同时处理5个请求。但是,如果请求依赖于其他I/O操作,将会发生什么呢?如果需要调用web服务该怎么办?

在"同步"场景中,当Request1进入并调用web服务时,Request1的线程将等待,直到来自web服务的响应到达。Request2、Request3、Request4和Request5也一样。当Request6进入时,服务器将返回一个HTTP 503响应("服务不可用"),因为所有5个线程都在等待web服务响应。此时,您的服务器无法再处理任何请求,直到其中一个请求完成并且线程已返回到线程池。

在"异步"场景中,Request1进入并调用web服务,Request1的线程不会等待web服务的响应,而是立即返回到线程池。Request2、Request3、Request4和Request5也一样。当Request6进入时,服务器有所有5个线程(假设没有任何web服务调用返回)来处理请求。这是"Async"的好处,因为它不会阻塞线程。这样你可以同时处理更多的请求。

您可以清楚地看到,这一切都取决于您在请求中所做的事情。如果请求正在做的工作需要纯粹的CPU关注(CPU密集型工作),那么异步将不会帮助你,因为无论是异步还是同步,CPU都被占用,不能做任何其他事情。因此,您的请求将不得不等待。注意你在异步操作中所做的事情。如果您为测试目的所做的全部工作是:

Thread.Sleep(2000);

那么你的线程仍然被占用,无论是同步还是异步(只有一种方法可以让线程睡觉,它不能睡觉,同时通过返回线程池来做工作)。

做一些真正异步的事情,例如,从一个大文件中读取,你会看到异步和同步的真正好处。

和为什么它与它要卸载到的线程池不同。

处理I/O请求的线程与处理这些ASP请求的线程不同。在某些情况下,它甚至不是同一台机器,例如,如果您调用另一台机器上的web服务或从另一台机器上的文件读取…你明白了。 更新1:

更多有用的信息是当你有这样的代码:

return new Task(() => Thread.Sleep(2000));

如果上面的代码正在被Request1的线程处理,它将被卸载到另一个线程(Request1, Request2, Request3或Request4)。另一个线程会休眠。所以本质上,它会让你付出更多,因为你切换了上下文,但你没有得到任何回报。因此,由于这里的上下文切换,您的异步版本将比同步版本慢。

此外,请记住,无论是同步还是异步,客户端必须等待的时间几乎是相同的(它不会更快)。唯一的好处是您的服务器可以处理更多的请求。工作仍然需要以这样或那样的方式完成(同步或异步)。