ThreadPool.SetMinThreads 不创建任何新线程

Pro*_*kov 5 .net c# multithreading threadpool .net-5

我试图弄清楚到底会ThreadPool.SetMinThreads产生什么影响。

根据官方文件说

设置在切换到管理线程创建和销毁的算法之前,当发出新请求时,线程池按需创建的最小线程数。

根据我的理解,作为一名开发人员,我应该能够控制如何按需旋转新线程的机制,因此它们会被创建并在空闲状态下等待,例如在我期望收到请求负载的情况下在特定时间。

这正是我最初认为SetMinThreads方法的设计目的。

但当我开始实际使用它时 - 我得到了非常奇怪的结果。

所以我有我的 ASP.NET .NET5 应用程序,并且在控制器操作中我有如下代码: ThreadPool.SetMinThreads(32000, 1000);

当然,我直觉地期望运行时为我创建 32K 工作线程和 1000 个 io 线程。

当我这样做,然后调用其他方法 - Process.GetCurrentProcess().Threads获取所有进程的线程,并打印它们的统计信息,我得到这样的东西

Standby - 17
Running - 4
Run Code Online (Sandbox Code Playgroud)

我认为应用程序可能需要一些时间来旋转新线程,所以我尝试了不同的延迟,1 分钟、5 分钟和 10 分钟。

但结果总是保持不变,我得到15-20 Standby和2-4 Running。

那么接下来的逻辑问题是——SetMinThreads方法到底在做什么?MSDN提供的描述似乎没有太大帮助。

还有另一个逻辑问题 - 如果我想强制 dotnet 在空闲状态下旋转 32K 新线程怎么办 - dotnet 是否为此提供了任何机制?

The*_*ias 6

设置按需立即创建的ThreadPool.SetMinThreads最小线程数。这是关键短语,而且确实很不直观。当前\xc2\xb9 (.NET 5) 有两种工作模式:ThreadPoolThreadPool

\n
    \n
  1. 当新的工作请求到达并且池中的所有线程都忙时,立即创建一个新线程以满足该请求。

    \n
  2. \n
  3. 当新的工作请求到达,并且池中的所有线程都忙时,将请求排队,并在创建新线程之前等待 1 秒,希望在此期间其中一个工作线程能够完成其当前工作,并且将可用于服务排队的请求。

    \n
  4. \n
\n

设置ThreadPool.SetMinThreads这两种模式之间的阈值。它无法让您控制当前活动的线程数量。这不是很令人满意,但事实就是如此。如果您想强制ThreadPool立即创建 1,000 个线程,除了调用ThreadPool.SetMinThreads(1000, 1000). 像这样的事情应该可以解决问题:

\n
ThreadPool.SetMinThreads(1000, 1000);\nTask[] tasks = Enumerable.Range(0, 1000)\n    .Select(_ => Task.Run(() => Thread.Sleep(100)))\n    .ToArray();\n
Run Code Online (Sandbox Code Playgroud)\n

老实说,我认为没有人这样做。创建一个新线程Thread对于人类来说相当快(在我的 PC 中每个线程大约需要 0.25 毫秒),因此对于接收人类请求的系统来说,创建线程的开销应该会产生任何可测量的影响。另一方面,当您希望线程执行少量工作(在纳秒范围内)时,例如在List<T>. 这就是为什么ThreadPool首先发明它的原因:为了分摊微小但大量工作负载的线程创建开销。

\n

请注意,创建新线程Thread也会产生内存成本,这通常比时间成本更重要:每个线程的堆栈至少需要1 MB RAM。因此,创建 32,000 个线程将占用 32 GB 内存,仅用于堆栈空间。这不是很有效。这就是为什么近年来异步编程在服务器端 Web 开发中变得如此重要,因为它允许用更少的线程完成更多的工作。

\n

\xc2\xb9没有什么可以阻止 Microsoft 工程师将来更改/调整其实现ThreadPool。据我所知,这种情况过去至少已经发生过一次。

\n

  • @TheodorZoulias 关于 500 毫秒——您可能还记得[文档](https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-management-faq#important-details -关于线程池增长)!Microsoft 表示:“...ThreadPool 将限制每 500 毫秒向一个线程注入新线程的速率” (2认同)