我正在阅读ASP.NET MVC 中的 AsyncControllers。
似乎它们存在的唯一原因是可以保存 IIS 线程,而将长时间运行的工作委托给常规 CLR 线程,这似乎更便宜。
我在这里有几个问题:
- 为什么这些 IIS 线程如此昂贵,以证明为支持异步控制器而构建的整个体系结构是合理的?
- 我如何知道/配置在我的 IIS 应用程序池中运行了多少个 IIS 线程?
我正在阅读ASP.NET MVC 中的 AsyncControllers。
似乎它们存在的唯一原因是可以保存 IIS 线程,而将长时间运行的工作委托给常规 CLR 线程,这似乎更便宜。
我在这里有几个问题:
ASP.NET processes requests by using threads from the .NET thread pool. The thread pool maintains a pool of threads that have already incurred the thread initialization costs. Therefore, these threads are easy to reuse. The .NET thread pool is also self-tuning. It monitors CPU and other resource utilization, and it adds new threads or trims the thread pool size as needed. You should generally avoid creating threads manually to perform work. Instead, use threads from the thread pool. At the same time, it is important to ensure that your application does not perform lengthy blocking operations that could quickly lead to thread pool starvation and rejected HTTP requests.
Disk I/O, web service calls, are all blocking. There are best optimized by using async calls. When you make an async call, asp.net frees your thread and the request will be assigned to another thread when the callback function is invoked.
To configure the number of threads you can set:
<system.web>
<applicationPool maxConcurrentRequestsPerCPU="50" maxConcurrentThreadsPerCPU="0" requestQueueLimit="5000"/>
</system.web>
Refer: ASP.NET Thread Usage on IIS 7.5, IIS 7.0, and IIS 6.0
These are the setting that Microsoft best practices recommend:
Note: The recommendations that are provided in this section are not rules. They are a starting point.
You would have to benchmark your application to find what works best for your application.
IIS 线程取自默认线程池,默认情况下受处理器内核数量限制。如果此线程池队列被备份,IIS 将停止响应请求。通过使用异步代码,可以在异步操作发生时将线程池线程返回到池中,从而使 IIS 能够为更多请求提供整体服务。
另一方面,自己生成一个新线程并不使用线程池线程。生成未经检查的独立线程数量也可能是一个问题,因此它不是解决 IIS 线程池问题的所有方法。无论哪种方式,通常都首选异步 IO。
至于更改线程池中的线程数,请查看此处。但是,您可能真的应该避免这样做。
我们的 Web 服务需要不时地提供100 个请求/秒,而其余时间为 1 个请求/秒。分析 IIS 日志,我们发现在发生突发事件时为此类调用提供服务大约需要28秒。
在我们的案例中,应用@nunespascal引用的Microsoft 最佳实践可将时间大幅缩短至 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);
这个解决方案来自Stuart Brierley在 2009 年撰写的一篇博客文章。我们从 2008 R2 到 2016 年成功地使用 Windows Server 对其进行了测试。
实际上,您链接的文章中所写的内容是不正确的。异步模式不能释放“超级昂贵的 IIS 工作线程”并在后台使用其他一些“廉价线程”。
异步模式只是为了释放线程。在不需要线程(最好甚至不需要本地机器)的情况下,您可以从中受益。
我可以举出两个示例场景(都是 I/O):
第一的:
几乎相同的第二个:
阅读 msdn 通常是安全的。您可以在此处获取有关异步模式的信息。