我是ASP.NET MVC中的reading about AsyncControllers。
似乎它们存在的唯一原因是,当长时间运行的工作委托给常规CLR线程时,可以保存IIS线程,这似乎更便宜。
我在这里有几个问题:
答案 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:
的设置注意:本节中提供的建议不是规则。他们是一个起点。
您必须对应用程序进行基准测试,以找出最适合您应用的方法。
答案 1 :(得分:6)
IIS线程取自默认线程池,默认情况下基于处理器核心数限制。如果此线程池队列被备份,IIS将停止响应请求。通过使用异步代码,可以在执行异步操作时将线程池线程返回到池中,从而允许IIS为整体请求提供更多服务。
另一方面,自己生成一个新线程不会使用线程池线程。产生一个未经检查的独立线程数也可能是一个问题,因此它不能解决所有修复IIS线程池问题。无论哪种方式,Async IO通常都是首选。
至于更改线程池中的线程数check here。但是,你应该真的避免这样做。
答案 2 :(得分:4)
实际上article you have linked中写的是不正确的。 异步模式不是免费的“超级昂贵的IIS工作者线程”,并在后台使用其他一些“廉价线程”。
异步模式只是为了释放线程。 在不需要线程的情况下(甚至不是本地机器),您可以从中受益。
我可以列举两个示例场景(两个I / O):
首先:
几乎相同的第二个:
阅读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年对其进行了成功测试。