在荷兰的Techday期间,Sanderson做了一个关于。的介绍
他解释说,当请求需要很长时间才能完成时,线程池中的所有线程都会变得繁忙,新的请求必须等待。服务器无法处理负载,一切都变慢了。
然后,他展示了异步new请求的使用如何提高性能,因为工作然后委托给另一个线程,线程池可以快速响应新传入的请求。他甚至演示了这一点,并展示了50个并发请求首先需要50 *1,但在异步行为到位之后,总共只有1,2 s。
但在看到这个之后我还有一些疑问。
发布于 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之前,这样做比重写代码完全异步要容易得多。
但是,这种方法存在一些问题:
因此,增加线程池的大小是一种解决方案,人们已经这样做了十年(即使是在微软自己的产品中),在内存和CPU使用方面,它的可伸缩性和效率都很低,而且您总是受到IO延迟的突然增加的摆布,这会导致饥饿。直到C# 5.0,异步代码的复杂性不值得为许多人带来麻烦。异步/等待将改变一切,就像现在一样,您可以从异步IO的可伸缩性中获益,同时编写简单的代码。
更多详细信息:http://msdn.microsoft.com/en-us/library/ff647787.aspx“在有机会执行额外的并行处理时,使用异步调用来调用ASP.NET服务或远程对象。在可能的情况下,避免对Web服务的同步(阻塞)调用,因为传出的Web服务调用是通过使用来自ASP.NET线程池的线程进行的。阻塞调用减少了处理其他传入请求的可用线程数。”
发布于 2012-02-26 13:56:51
SynchronizationContext
的SynchronizationContext
实现管理。您可以在我的MSDN文章中了解更多有关我的MSDN文章的内容--它介绍了ASP.NET的SynchronizationContext
如何工作以及await
如何使用SynchronizationContext
。在异步/等待之前,ASP.NET异步处理是可能的--您可以使用异步页面,并使用EAP组件,例如WebClient
(基于事件的异步编程是一种基于SynchronizationContext
的异步编程方式)。异步/等待也使用SynchronizationContext
,但语法要简单得多。
发布于 2014-08-11 19:49:05
将线程池想象成一组工作人员,您已经雇用了这些人来完成工作。您的工作人员为您的代码运行快速cpu指令。
现在,您的工作恰好依赖于另一个慢的家伙的工作;慢的家伙是磁盘或网络。例如,你的工作可以有两个部分,一个部分必须在慢的人的工作之前执行,另一个部分必须在慢的人的工作之后执行。
你会如何建议你的工人做你的工作?你会对每个工人说--“先做第一部分,然后等到那个慢条斯理的人完成,然后再做第二部分”?你会不会增加你的员工数量,因为他们似乎都在等待那个迟钝的家伙,而你却无法满足新客户的需求?不是的!
相反,您将要求每个员工完成第一部分,并要求慢的人回来,并在完成后将一条消息放入队列中。您将告诉每个工作人员(或者可能是工作人员的一个专用子集)在队列中查找已完成的消息并完成第二部分的工作。
上面提到的智能内核是操作系统为缓慢磁盘和网络IO完成消息维护这样一个队列的能力。
https://stackoverflow.com/questions/9453560
复制相似问题