为啥通过调用Task.Run和ThreadPool.QueueUserWorkItem排队到ThreadPool时线程数增加了不止一个?
Posted
技术标签:
【中文标题】为啥通过调用Task.Run和ThreadPool.QueueUserWorkItem排队到ThreadPool时线程数增加了不止一个?【英文标题】:Why threads count is increased by more than one when queuing to ThreadPool by calling Task.Run and ThreadPool.QueueUserWorkItem?为什么通过调用Task.Run和ThreadPool.QueueUserWorkItem排队到ThreadPool时线程数增加了不止一个? 【发布时间】:2020-03-11 16:27:03 【问题描述】:我试图在 Thread
的帮助下计算控制台应用程序中正在运行的线程数:
new Thread(() =>
while (true)
Thread.Sleep(500);
Console.WriteLine(System.Diagnostics.Process.GetCurrentProcess().Threads.Count);
).Start();
然后我开始了新的Thread
,其中包含非常简单的执行逻辑。毫无疑问,线程数增加了1
。对于ThreadPool.QueueUserWorkItem
,它增加了 3。
并对Task.Run(() => ...)
做了同样的测试。令人惊讶的是,线程数增加了4
或有时5
。不幸的是,我无法理解原因。
这里是完整的测试代码:
static void Main(string[] args)
new Thread(() =>
while (true)
Thread.Sleep(500);
Console.WriteLine(System.Diagnostics.Process.GetCurrentProcess().Threads.Count);
).Start();
//Task.Run(() =>
//
// Thread.Sleep(5000);
//); // thread count is 12
//new TaskFactory().StartNew(() =>
//
// Thread.Sleep(5000);
//); // thread count is 12
//ThreadPool.QueueUserWorkItem((onj) =>
//
// Thread.Sleep(5000);
//); // thread count is 9
//new Thread(() =>
//
// Thread.Sleep(5000);
//).Start(); // thread count is 7
Console.ReadLine();
我的问题是,为什么运行新任务会使线程数增加 4 或 5?为什么为线程池排队工作项会使线程数增加 3?
【问题讨论】:
@Fredou 为了获得计数,我在问题的第一行与您分享了专门的线程 与Task
和Task<T>
合作的要点之一是专注于手头的工作,而不是机制 .为什么您如此关心 runtime 在任何特定时间恰好运行了多少线程?
@Damien_The_Unbeliever 我正在比较两种不同实现的运行线程数。因为,运行线程越少,上下文切换就越少,依此类推。并且无法找出为什么计数如此增加。然后,我编写了那个简单的代码来找出差异。我相信它在某处有记录,但我没有运气找到它
请注意,线程出现在GetCurrentProcess().Threads
中并不意味着它正在运行。这可能是一个没有做任何事情的线程池。
@canton7 我们在同一条路上。我会稍等一下,然后可能会删除答案。我想这可能是我忽略了一些细节。
【参考方案1】:
线程池使用complicated mechanism 来确定将运行多少线程。
当您通过调用QueueUserItem
或创建Task
将工作排队到线程池时,线程池将使用默认的初始线程数进行初始化,通常为四个。
【讨论】:
您能否分享一下有关线程池中默认初始线程数的文档? @FarhadJabiyev 你可以调用ThreadPool.GetMinThreads
方法来获取这些值,虽然文档说:当需求低时,线程池线程的实际数量可能会低于最小值。在我的 PC 中是 4 个(和 4 个 I/O 完成线程)。
@Nick 感谢您的回答。它克服了我的困惑。也会尝试阅读那篇文章。以上是关于为啥通过调用Task.Run和ThreadPool.QueueUserWorkItem排队到ThreadPool时线程数增加了不止一个?的主要内容,如果未能解决你的问题,请参考以下文章
为啥不等待 Task.Run() 同步回 UI 线程/原始上下文?
CS0121'Task.Run之间的调用不明确 (Func键 )'和'Task.Run(Func )”