当 ThreadPool 中的活动线程数大于 ThreadPool.GetMinThreads() 时启动任务
Starting a task when the number of active threads in ThreadPool is greater than ThreadPool.GetMinThreads()
摘自对我之前的一个问题的回答
():
"It's not the MAX worker threads value you need to look at - it's the
MIN value you get via ThreadPool.GetMinThreads(). The max value is the
absolute maximum threads that can be active. The min value is the
number to always keep active. If you try to start a thread when the
number of active threads is less than max (and greater than min)
you'll see a 2 second delay."
所以,我准备了一个示例代码来测试它:
ThreadPool.GetMinThreads()
returns 我的机器是“8”,我 运行 我本地机器上的代码。
我的代码如下所示:
Task task = null;
int workerThreads = 0;
int completionPortThreads = 0;
ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads);
Logger.WriteInfo(LogCode.EMPTY_INFO, workerThreads.ToString());**returns "8"**
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread1");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread1");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread2");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread2");
while (true)
{
DoSomthing();
}
});
;
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread3");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread3");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread4");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread4");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread5");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread5");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread6");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread6");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread7");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread7");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread8");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread8");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread9");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread9");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread10");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread10");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread11");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread11");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread12");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread12");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread13");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread13");
while (true)
{
DoSomthing();
}
});
private void DoSomthing()
{
int j = 1;
for (int i = 0; i < 2000; i++)
{
j = i * i;
}
}
Logger class 仅使用 log4net.dll。
因此,ThreadPool.GetMinThreads() returns 8 用于我的机器。
最小值是始终保持活动状态的数字。如果您尝试在活动线程数小于最大值(且大于最小值)时启动线程,您将看到 2 秒的延迟。
因此,对于线程号 9 等等:
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread9");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread9");
while (true)
{
DoSomthing();
}
});
我预计
之间会有 2 秒的延迟
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread9");
和
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread9");
因为当活动线程数大于 min(大于 8)时,我尝试启动一个线程(从线程池)。
实际结果是只有几毫秒的延迟
(不到半秒)所有线程 9 到 13。
为什么至少没有2秒的延迟?我的意思是,我的线程池中的所有活动线程都很忙,并且对于线程 9 需要分配另一个线程,所以应该有延迟。
写完这个示例应用程序后,我不确定我上一个问题中的场景。
这里有几个问题。
首先是,你正在使用你可能不应该使用的Task.Factory.StartNew
,在大多数情况下你应该使用更现代的Task.Run
有很多关于此的问题和博客。
其次,您引用的问题引用的文档比当前框架更旧。文档已更改。它曾经规定了创建线程的毫秒延迟。
第三,任务不是线程
我对这个的理解是task scheduler(看你用的是哪个)用启发式的方式来判断是否要给你一个线程在每个类别中,没有任意的毫秒延迟。
文档目前所说的是。
The thread pool provides new worker threads or I/O completion threads
on demand until it reaches the minimum for each category. When a
minimum is reached, the thread pool can create additional threads in
that category or wait until some tasks complete.
事实是,如果您依赖任务调度程序的典型行为以特定速度分配线程,那么您肯定做错了什么。这是一个实现细节,可能会因版本而异。充其量您可以增加最少的线程数,但任务调度程序的工作是在很大程度上将您从这一级别的细节中抽象出来。它旨在为您做最好的事情。
如果您需要一定数量的线程,要么构建您自己的任务调度程序,要么创建您自己的线程并一起跳过任务调度程序
嗯,查看 ThreadPool
的 MSDN 文档,我没有发现任何与达到大于最小值的值时延迟 2 秒相关的内容,我认为这不是准确的答案,因为延迟取决于与硬件和 OS 相关的许多因素,指定了以下内容:
By default, the minimum number of threads is set to the number of processors on a system. When the minimum is reached, the thread pool can create additional threads in that category or wait until some tasks complete. Beginning with the .NET Framework 4, the thread pool creates and destroys threads in order to optimize throughput, which is defined as the number of tasks that complete per unit of time. Too few threads might not make optimal use of available resources, whereas too many threads could increase resource contention.
GetMinThreads 的文档如下:
Retrieves 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 秒延迟的来源是什么,是在他的机器上测试的吗?
但是,如果您需要有关此的更多信息,.NET 框架 Source 是 public 您可以深入检查算法,但您也不会获得延迟的静态数字,因为硬件和 OS 依赖因素。
摘自对我之前的一个问题的回答
(
"It's not the MAX worker threads value you need to look at - it's the MIN value you get via ThreadPool.GetMinThreads(). The max value is the absolute maximum threads that can be active. The min value is the number to always keep active. If you try to start a thread when the number of active threads is less than max (and greater than min) you'll see a 2 second delay."
所以,我准备了一个示例代码来测试它:
ThreadPool.GetMinThreads()
returns 我的机器是“8”,我 运行 我本地机器上的代码。
我的代码如下所示:
Task task = null;
int workerThreads = 0;
int completionPortThreads = 0;
ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads);
Logger.WriteInfo(LogCode.EMPTY_INFO, workerThreads.ToString());**returns "8"**
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread1");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread1");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread2");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread2");
while (true)
{
DoSomthing();
}
});
;
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread3");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread3");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread4");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread4");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread5");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread5");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread6");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread6");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread7");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread7");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread8");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread8");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread9");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread9");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread10");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread10");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread11");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread11");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread12");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread12");
while (true)
{
DoSomthing();
}
});
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread13");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread13");
while (true)
{
DoSomthing();
}
});
private void DoSomthing()
{
int j = 1;
for (int i = 0; i < 2000; i++)
{
j = i * i;
}
}
Logger class 仅使用 log4net.dll。 因此,ThreadPool.GetMinThreads() returns 8 用于我的机器。 最小值是始终保持活动状态的数字。如果您尝试在活动线程数小于最大值(且大于最小值)时启动线程,您将看到 2 秒的延迟。
因此,对于线程号 9 等等:
Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread9");
task = Task.Factory.StartNew(() =>
{
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread9");
while (true)
{
DoSomthing();
}
});
我预计
之间会有 2 秒的延迟Logger.WriteInfo(LogCode.EMPTY_INFO, "before thread9");
和
Logger.WriteInfo(LogCode.EMPTY_INFO, "after thread9");
因为当活动线程数大于 min(大于 8)时,我尝试启动一个线程(从线程池)。 实际结果是只有几毫秒的延迟 (不到半秒)所有线程 9 到 13。
为什么至少没有2秒的延迟?我的意思是,我的线程池中的所有活动线程都很忙,并且对于线程 9 需要分配另一个线程,所以应该有延迟。
写完这个示例应用程序后,我不确定我上一个问题中的场景。
这里有几个问题。
首先是,你正在使用你可能不应该使用的
Task.Factory.StartNew
,在大多数情况下你应该使用更现代的Task.Run
有很多关于此的问题和博客。其次,您引用的问题引用的文档比当前框架更旧。文档已更改。它曾经规定了创建线程的毫秒延迟。
第三,任务不是线程
我对这个的理解是task scheduler(看你用的是哪个)用启发式的方式来判断是否要给你一个线程在每个类别中,没有任意的毫秒延迟。
文档目前所说的是。
The thread pool provides new worker threads or I/O completion threads on demand until it reaches the minimum for each category. When a minimum is reached, the thread pool can create additional threads in that category or wait until some tasks complete.
事实是,如果您依赖任务调度程序的典型行为以特定速度分配线程,那么您肯定做错了什么。这是一个实现细节,可能会因版本而异。充其量您可以增加最少的线程数,但任务调度程序的工作是在很大程度上将您从这一级别的细节中抽象出来。它旨在为您做最好的事情。
如果您需要一定数量的线程,要么构建您自己的任务调度程序,要么创建您自己的线程并一起跳过任务调度程序
嗯,查看 ThreadPool
的 MSDN 文档,我没有发现任何与达到大于最小值的值时延迟 2 秒相关的内容,我认为这不是准确的答案,因为延迟取决于与硬件和 OS 相关的许多因素,指定了以下内容:
By default, the minimum number of threads is set to the number of processors on a system. When the minimum is reached, the thread pool can create additional threads in that category or wait until some tasks complete. Beginning with the .NET Framework 4, the thread pool creates and destroys threads in order to optimize throughput, which is defined as the number of tasks that complete per unit of time. Too few threads might not make optimal use of available resources, whereas too many threads could increase resource contention.
GetMinThreads 的文档如下:
Retrieves 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 秒延迟的来源是什么,是在他的机器上测试的吗?
但是,如果您需要有关此的更多信息,.NET 框架 Source 是 public 您可以深入检查算法,但您也不会获得延迟的静态数字,因为硬件和 OS 依赖因素。