首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么要使用异步请求而不是使用更大的线程池?

为什么要使用异步请求而不是使用更大的线程池?
EN

Stack Overflow用户
提问于 2012-02-26 13:43:22
回答 3查看 15.8K关注 0票数 70

在荷兰的Techday期间,Sanderson做了一个关于的介绍

他解释说,当请求需要很长时间才能完成时,线程池中的所有线程都会变得繁忙,新的请求必须等待。服务器无法处理负载,一切都变慢了。

然后,他展示了异步new请求的使用如何提高性能,因为工作然后委托给另一个线程,线程池可以快速响应新传入的请求。他甚至演示了这一点,并展示了50个并发请求首先需要50 *1,但在异步行为到位之后,总共只有1,2 s。

但在看到这个之后我还有一些疑问。

  1. 为什么我们不能使用一个更大的线程池呢?使用异步/等待不是要以更慢的速度启动另一个线程,而只是从一开始就增加线程池吗?这不像我们运行的服务器突然得到更多的线程或什么的?
  2. 来自用户的请求仍在等待异步线程完成。如果池中的线程正在做其他事情,“UI”线程如何保持忙碌?Steve提到了“一个智能内核,它知道什么时候做完事情”。这是怎么工作的?
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-02-27 13:56:21

这是一个非常好的问题,理解异步IO为什么如此重要是关键。将新的异步/等待特性添加到C# 5.0的原因是为了简化异步代码的编写。对服务器上的异步处理的支持并不是新的,但是,它自ASP.NET 2.0以来就已经存在了。

正如Steve向您展示的,通过同步处理,ASP.NET (和WCF)中的每个请求都从线程池中获取一个线程。他演示的问题是一个众所周知的问题,称为“线程池饥饿”。如果在服务器上执行同步IO,则线程池线程将在IO期间保持阻塞(不做任何操作)。由于在加载下线程池中的线程数量受到限制,这可能导致所有线程池线程都被阻塞等待IO,并且请求开始排队,导致响应时间增加。由于所有线程都在等待IO完成,您将看到CPU占用接近0% (即使响应时间过高)。

您要问的问题(,为什么我们不能只使用更大的线程池?)是一个非常好的问题。事实上,到目前为止,大多数人都是这样解决线程池饥饿问题的:线程池上只有更多的线程。Microsoft的一些文档甚至指出,在可能出现线程池饥饿的情况下,可以将其作为一种修复。这是一个可以接受的解决方案,在C# 5.0之前,这样做比重写代码完全异步要容易得多。

但是,这种方法存在一些问题:

  • 没有在所有情况下都有效的值,:您需要的线程池线程的数量与IO的持续时间和服务器上的负载成线性关系。不幸的是,IO延迟大多是不可预测的。下面是一个例子:假设您向ASP.NET应用程序中的第三方web服务发出HTTP请求,这需要大约2秒的时间来完成。您遇到线程池饥饿,所以您决定将线程池大小增加到,比方说,200个线程,然后它又开始正常工作了。问题是,也许下个星期,web服务将出现技术问题,从而将它们的响应时间增加到10秒。突然之间,线程池饥饿又回来了,因为线程被阻塞的时间是原来的5倍,所以现在需要将这个数字增加5倍,增加到1000个线程。
  • 可伸缩性和性能:第二个问题是,如果这样做,每个请求仍将使用一个线程。线程是一种昂贵的资源。.NET中的每个托管线程都需要为堆栈分配1MB的内存。对于一个使IO持续5秒、每秒加载500个请求的网页,您将需要线程池中的2500个线程,这意味着对于那些将无所事事的线程堆栈来说,需要2.5GB的内存。然后是上下文切换问题,这将严重影响机器的性能(影响机器上的所有服务,而不仅仅是web应用程序)。尽管Windows在忽略等待线程方面做得相当好,但它的设计并不能处理这么多线程。请记住,当运行的线程数等于机器上逻辑CPU的数量(通常不超过16个)时,效率最高。

因此,增加线程池的大小是一种解决方案,人们已经这样做了十年(即使是在微软自己的产品中),在内存和CPU使用方面,它的可伸缩性和效率都很低,而且您总是受到IO延迟的突然增加的摆布,这会导致饥饿。直到C# 5.0,异步代码的复杂性不值得为许多人带来麻烦。异步/等待将改变一切,就像现在一样,您可以从异步IO的可伸缩性中获益,同时编写简单的代码。

更多详细信息:http://msdn.microsoft.com/en-us/library/ff647787.aspx“在有机会执行额外的并行处理时,使用异步调用来调用ASP.NET服务或远程对象。在可能的情况下,避免对Web服务的同步(阻塞)调用,因为传出的Web服务调用是通过使用来自ASP.NET线程池的线程进行的。阻塞调用减少了处理其他传入请求的可用线程数。”

票数 68
EN

Stack Overflow用户

发布于 2012-02-26 13:56:51

  1. 异步/等待不是基于线程,而是基于异步处理。在ASP.NET中执行异步等待时,请求线程将返回到线程池,因此在异步操作完成之前没有线程为该请求提供服务。由于请求开销低于线程开销,这意味着异步/等待可以比线程池更好地扩展。
  2. 请求有未完成的异步操作的计数。此计数由SynchronizationContextSynchronizationContext实现管理。您可以在我的MSDN文章中了解更多有关我的MSDN文章的内容--它介绍了ASP.NET的SynchronizationContext如何工作以及await如何使用SynchronizationContext

在异步/等待之前,ASP.NET异步处理是可能的--您可以使用异步页面,并使用EAP组件,例如WebClient (基于事件的异步编程是一种基于SynchronizationContext的异步编程方式)。异步/等待也使用SynchronizationContext,但语法要简单得多。

票数 32
EN

Stack Overflow用户

发布于 2014-08-11 19:49:05

将线程池想象成一组工作人员,您已经雇用了这些人来完成工作。您的工作人员为您的代码运行快速cpu指令。

现在,您的工作恰好依赖于另一个慢的家伙的工作;慢的家伙是磁盘网络。例如,你的工作可以有两个部分,一个部分必须在慢的人的工作之前执行,另一个部分必须在慢的人的工作之后执行。

你会如何建议你的工人做你的工作?你会对每个工人说--“先做第一部分,然后等到那个慢条斯理的人完成,然后再做第二部分”?你会不会增加你的员工数量,因为他们似乎都在等待那个迟钝的家伙,而你却无法满足新客户的需求?不是的!

相反,您将要求每个员工完成第一部分,并要求慢的人回来,并在完成后将一条消息放入队列中。您将告诉每个工作人员(或者可能是工作人员的一个专用子集)在队列中查找已完成的消息并完成第二部分的工作。

上面提到的智能内核是操作系统为缓慢磁盘和网络IO完成消息维护这样一个队列的能力。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9453560

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档