为什么IIS线程与常规CLR线程相比如此珍贵?

我正在阅读关于 ASP.NET MVC中的AsyncControllers 。

看起来,它们存在的唯一原因是IIS线程可以被保存,而长时间运行的工作被委托给常规的CLR线程,似乎更便宜。

我在这里有几个问题:

  • 为什么这些IIS线程如此昂贵,无法certificate为支持asynchronous控制器而构build的整个体系结构?
  • 我如何知道/configuration在IIS应用程序池中运行多less个IIS线程?

ASP.NET通过使用.NET线程池中的线程来处理请求。 线程池维护已经产生线程初始化成本的线程池。 因此,这些线程很容易重用。 .NET线程池也是自我调整的。 它监视CPU和其他资源利用率,并根据需要添加新线程或修剪线程池大小。 通常应避免手动创build线程来执行工作。 而是使用线程池中的线程。 同时,确保您的应用程序不执行冗长的阻塞操作很重要,这些操作可能会导致线程池匮乏并拒绝HTTP请求。

磁盘I / O,Web服务调用都是阻塞的。 最好通过使用asynchronous调用进行优化。 当您进行asynchronous调用时,asp.net释放您的线程,并在callback函数被调用时将请求分配给另一个线程。

要configuration可以设置的线程数:

<system.web> <applicationPool maxConcurrentRequestsPerCPU="50" maxConcurrentThreadsPerCPU="0" requestQueueLimit="5000"/> </system.web> 

请参阅: IIS 7.5,IIS 7.0和IIS 6.0上的ASP.NET线程使用情况

这些是Microsoft最佳实践build议的设置:

  • 将最大连接设置为12 *个CPU 。 此设置控制您可以从客户端启动的传出HTTP连接的最大数量。 在这种情况下,ASP.NET是客户端。 将最大连接设置为12 *个CPU。
  • 将maxIoThreads设置为100 。 此设置控制.NET线程池中的最大I / O线程数。 该数字将自动乘以可用的CPU数量。 将maxloThreads设置为100。
  • 将maxWorkerThreads设置为100 。 此设置控制线程池中的最大工作线程数。 这个数字然后自动乘以可用的CPU数量。 将maxWorkerThreads设置为100。
  • 将minFreeThreads设置为88 *个CPU 。 如果线程池中可用线程的数量低于此设置的值,工作进程将使用此设置对所有传入请求进行排队。 此设置有效地限制了可以同时运行到maxWorkerThreads – minFreeThreads的请求的数量。 将minFreeThreads设置为88 *个CPU。 这限制了并发请求的数量为12(假设maxWorkerThreads是100)。
  • 将minLocalRequestFreeThreads设置为76 *个CPU 。 如果线程池中的可用线程数量低于此数量,则该工作进程将使用此设置对来自本地主机(Web应用程序向本地Web服务发送请求的位置)的请求进行排队。 此设置与minFreeThreads类似,但仅适用于本地计算机的本地主机请求。 将minLocalRequestFreeThreads设置为76 *个CPU。

注意 :本节提供的build议不是规则。 他们是一个起点。

您必须对您的应用程序进行基准testing,以找出最适合您应用程序的内容。

IIS线程取自默认线程池,默认线程池基于处理器内核的数量而受到默认限制。 如果此线程池队列已备份,IIS将停止响应请求。 通过使用asynchronous代码,可以在执行asynchronous操作时将线程池线程返回到池,从而使IIS能够为整个服务提供更多的请求。

另一方面,自己产生一个新线程不会使用线程池线程。 产生一个未经检查的独立线程数量也可能是一个问题,所以这不是一个解决IIS线程池问题的全部办法。 asynchronousIO通常是首选的方式之一。

至于改变线程池中的线程数量, 请点击这里 。 但是,你应该避免这样做。

其实你所链接的文章写的是不正确的。 asynchronous模式不是免费的“超级昂贵的IIS工作线程”,并在后台使用一些“廉价线程”。

asynchronous模式只是为了释放线程。 在不需要线程的情况下(甚至不是本地机器),您可以从中受益。

我可以命名两个示例场景(都是I / O):

第一:

  1. 的BeginRequest
  2. 开始asynchronous文件读取
  3. 在文件读取时,你不需要你的线程 – 所以其他请求可以使用它。
  4. 文件读取结束 – 您从应用程序池中获得线程。
  5. 请求结束。

而且几乎相同的第二:

  1. 的BeginRequest
  2. 开始对WCF服务的asynchronous调用。
  3. 我们可以离开我们的机器,不需要我们的线程 – 所以其他请求可以使用它。
  4. 我们从远程服务获得响应 – 我们从应用程序池中获取一些线程以继续。
  5. 请求结束。

读取msdn通常是安全的。 你可以在这里获得有关asynchronous模式的信息 。

我们的Web服务需要不时地提供100个请求/秒,而剩下的时间是1个请求/秒。 Analazyng IIS日志,我们发现它发生大约28时,突发发生服务这样的电话。

应用@nunespascal引用的微软最佳实践在我们的案例中大大缩短了1秒的时间

以下是我们在部署生产服务器时使用的Powershell脚本。 它更新machine.config采取逻辑处理器数量的计数。

 <# Get and backup current machine.config #> $path = "C:\Windows\Microsoft.Net\Framework\v4.0.30319\Config\machine.config"; $xml = [xml] (get-content($path)); $xml.Save($path + "-" + (Get-Date -Format "yyyyMMdd-HHmm" ) + ".bak"); <# Get number of physical CPU #> $physicalCPUs = ([ARRAY](Get-WmiObject Win32_Processor)).Count; <# Get number of logical processors #> $logicalProcessors = (([ARRAY](Get-WmiObject Win32_Processor))[0] | Select-Object “numberOfLogicalProcessors").numberOfLogicalProcessors * $physicalCPUs; <# Set Number of connection in system.net/connectionManagement #> $systemNet = $xml.configuration["system.net"]; if (-not $systemNet){ $systemNet = $xml.configuration.AppendChild($xml.CreateElement("system.net")); } $connectionManagement = $systemNet.connectionManagement; if (-not $connectionManagement){ $connectionManagement = $systemNet.AppendChild($xml.CreateElement("connectionManagement")); } $add = $connectionManagement.add; if(-not $add){ $add = $connectionManagement.AppendChild($xml.CreateElement("add")) ; } $add.SetAttribute("address","*"); $add.SetAttribute("maxconnection", [string]($logicalProcessors * 12) ); <# Set several thread settings in system.web/processModel #> $systemWeb = $xml.configuration["system.web"]; if (-not $systemWeb){ $systemWeb = $xml.configuration.AppendChild($xml.CreateElement("system.web")); } $processModel = $systemWeb.processModel; if (-not $processModel){ $processModel = $systemWeb.AppendChild($xml.CreateElement("processModel")); } $processModel.SetAttribute("autoConfig","true"); $processModel.SetAttribute("maxWorkerThreads","100"); $processModel.SetAttribute("maxIoThreads","100"); $processModel.SetAttribute("minWorkerThreads","50"); $processModel.SetAttribute("minIoThreads","50"); <# Set other thread settings in system.web/httRuntime #> $httpRuntime = $systemWeb.httpRuntime; if(-not $httpRuntime){ $httpRuntime = $systemWeb.AppendChild($xml.CreateElement("httpRuntime")); } $httpRuntime.SetAttribute("minFreeThreads",[string]($logicalProcessors * 88)); $httpRuntime.SetAttribute("minLocalRequestFreeThreads",[string]($logicalProcessors * 76)); <#Save modified machine.config#> $xml.Save($path); 

这个解决scheme是从2009年Stuart Brierley的博客文章中find我们的。我们用Windows Server 2008 R2到2016年成功testing了它。