在默认配置下,ASP.NET Core 应用启动时线程池中的线程数等于 CPU 的核心数,比如4核服务器的线程数就是4,详见之前的博文 ASP.NET Core 默认线程池大小是多少。
ThreadPool.ThreadCount: 4, Minimum work threads: 4, Minimum completion port threads: 4
而这点线程对高并发应用来说都不够塞牙缝。虽然 ASP.NET Core runtime 会在线程不够用时自动创建线程,但是每秒只能创建1-2个线程,等它创建好,黄花菜都凉了。
为了解决高并发场景下应用刚刚启动后的一段时间内线程不够用的问题,想在启动时就让线程池满血,比如让线程池有50个线程,请问有什么预热方法可以实现?
检查线程池线程数量的代码如下(放在 Startup.Configure 方法中):
logger.LogInformation($"ThreadPool.ThreadCount: {ThreadPool.ThreadCount}");
注:
1)ThreadPool.SetMinThreads(50, 50)
代码与 COMPlus_ThreadPool_ForceMinWorkerThreads=32
环境变量都是黄花菜都凉的方法,不可行。
Sets the minimum number of threads the thread pool creates on demand, as new requests are made, before switching to an algorithm for managing thread creation and destruction.
2)检验方法是在 Startup 中得到 ThreadPool.ThreadCount 的值为 50 。
3).NET Core 的版本 3.0 Preview 8 。
线程不够用现场证据
ThreadPool.ThreadCount: 5, Pending work item count: 851
直接在 Startup 里开 50 个线程呗。
if (ThreadPool.SetMinThreads(50, 50))
{
Parallel.For(0, 50, a => Thread.Sleep(1000));
}
好方法。
这里的 Sleep 1 秒钟是有什么作用吗
@墨墨墨墨小宇: 没有特殊的意义,只是故意让线程卡死一会,阻止线程被重用
通常的线程池(因为自己可以搞一套实现线程池)是用到那么多,才有那么多线程,超过阀值则等待池内有可用时去使用。
因此想 在启动就有很多线程,那么你可以在启动时,去使用 很多线程【姑且叫任务TaskAs】(每个线程需保证一定时间,这个不同机器,不同指令集cpu肯定无法完全预知),但是 如果 到了TaskAs 已经跑到差不多,线程池开始回收释放了(线程数又开始下降),你的Core任务TaskBs还没来...,那么仍然无法达到一个峰值线程数。
当然实际上Task应该没你说的那么夸张 —— Task为了节约已经不是从前的用完去销毁线程本身。
因此一个比较好的方式是,自行构建线程池,策略都可以自己定义,你可以定40,而且让这40不回收。Core里面TaskBs的调用使用自己的线程池。
自己定义线程池 可还行 2333
自己定义应该没问题,虽然会占用一定的资源,但是胜在比较稳定,线程用不用都会在哪里准备着。
据说,orleans里面的调度器,1秒内是可以创建1K的线程的。看博客是这么介绍的,但是没看源码。不知道它是怎么做到的。
我.net core 2.2环境下遇到一样的问题。
默认线程池最小线程数是和cpu核数相关。当程序已启动就遇到高并发的请求时,如果请求处理时间会比较长,asp.net core进程启动时的默认处理线程数是一定不够用的。而且线程数增加也很慢,差不多1s增加1个左右,导致很多请求被拒绝。
后来想通过将线程池的最小线程数调大去解决问题,但是设置1k以上时,SetMinThreads返回值为false,设置不生效。
然而一个偶然的机会我发现,SetMinThreads可以设置1k以上的最小线程数了。需用SetMaxThreads先设置最大线程数,之后再SetMinThreads设置最小线程数。奇迹这样发生了……
而且更诡异的是SetMaxThreads设置一个比以前小的值,之后再调用SetMinThreads设置最小线程数也是OK的。
设置OK之后程序虽然程序的线程数并不会立马增加,但是一旦遇到高并发请求,线程数增加是非常快速的。差不多1秒几十个线程左右。当并发量降低之后,线程数也会降低。但是当并发再次增高的时候,线程数的增加会比之前更快(一两秒就能恢复到2k水平)。
谢谢分享!
io thread 默认最大值是1000,所以直接SetMinThreads超过1000,会不成功;
实验过确实是这样的 之前以为SetMinThreads之后 程序中线程池最小是这么多 实际上你设置之后还是会自己调整 但是线程启动的比较快 我估计这个设置应该是更底层的资源申请 我一般都是设置在预估值的1.5倍左右
为啥我的ThreadPool.ThreadCount报错呢,没找到这个定义
– MrNice 5年前@MrNice: 我用的是 .NET Core 3.0
– dudu 5年前