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

时间:2012-09-06 16:45:18

标签: asp.net .net iis asynchronous

我是ASP.NET MVC中的reading about AsyncControllers

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

我在这里有几个问题:

  • 为什么这些IIS线程如此昂贵,以证明为支持异步控制器而构建的整个架构?
  • 如何知道/配置IIS应用程序池中运行的IIS线程数?

4 个答案:

答案 0 :(得分:48)

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

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

配置您可以设置的线程数:

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

参考:ASP.NET Thread Usage on IIS 7.5, IIS 7.0, and IIS 6.0

这些是Microsoft best practices recommend

的设置
  • 将maxconnection设置为12 *#的CPU 。此设置控制可以从客户端启动的最大传出HTTP连接数。在这种情况下,ASP.NET是客户端。将maxconnection设置为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 。如果线程池中的可用线程数低于此数,则工作进程将此设置用于对来自localhost(Web应用程序将请求发送到本地Web服务的请求)的请求进行排队。此设置类似于minFreeThreads,但它仅适用于来自本地计算机的localhost请求。将minLocalRequestFreeThreads设置为76 * #CPU。

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

您必须对应用程序进行基准测试,以找出最适合您应用的方法。

答案 1 :(得分:6)

IIS线程取自默认线程池,默认情况下基于处理器核心数限制。如果此线程池队列被备份,IIS将停止响应请求。通过使用异步代码,可以在执行异步操作时将线程池线程返回到池中,从而允许IIS为整体请求提供更多服务。

另一方面,自己生成一个新线程不会使用线程池线程。产生一个未经检查的独立线程数也可能是一个问题,因此它不能解决所有修复IIS线程池问题。无论哪种方式,Async IO通常都是首选。

至于更改线程池中的线程数check here。但是,你应该真的避免这样做。

答案 2 :(得分:4)

实际上article you have linked中写的是不正确的。 异步模式不是免费的“超级昂贵的IIS工作者线程”,并在后台使用其他一些“廉价线程”。

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

我可以列举两个示例场景(两个I / O):

首先:

  1. 的BeginRequest
  2. 开始异步文件读取
  3. 在文件读取期间,您不需要您的线程 - 因此其他请求可以使用它。
  4. 文件读取结束 - 您从应用程序池中获取线程。
  5. 请求完成。
  6. 几乎相同的第二个:

    1. 的BeginRequest
    2. 开始异步调用WCF服务。
    3. 我们可以离开我们的机器而不需要我们的线程 - 所以其他请求可以使用它。
    4. 我们从远程服务获得响应 - 我们从应用程序池中获取一些线程以继续。
    5. 请求完成。
    6. 阅读msdn通常是安全的。您可以获取有关异步模式here的信息。

答案 3 :(得分:3)

我们的Web服务需要不时地提供 100 requets / second ,而其余的时间则是1请求/秒。 Analazyng IIS日志我们发现,当发生突发以提供此类呼叫时,它需要 28s

在我们的案例中,@ nunespascal 引用的Microsoft best practices大大减少了1s 的时间。

下面是我们部署生产服务器时目前使用的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);

此解决方案于2009年从博客article witten by Stuart Brierley传到我们这里。我们使用Windows Server从2008 R2到2016年对其进行了成功测试。