如果我对ThreadPool工作方式的理解是正确的,那么其目的之一是限制在给定时间可以创建的进程中的工作线程数。例如,如果将MaxThreads设置为5,然后将QueueUserWorkItem调用30次,则将向ThreadPool发出30个请求,但这些请求中只有5个将由新线程提供服务,而其他25个请求将被添加到队列中并且随着先前的请求完成并且现有线程变得可用,一次服务一个。
但是,在下面的代码中,对Thread.Sleep(-1)的调用保证DoSomething()方法永远不会返回,这意味着当前线程永远不会对后续请求可用。
但是我对ThreadPool工作方式的理解不正确,因为如果它是正确的,下面的代码只打印数字0-4而不是0-29。
有人可以解释一下ThreadPool是如何工作的,以及为什么下面的代码没有做我认为它应该做的事情?
static void DoSomething(object n)
{
Console.WriteLine(n);
Thread.Sleep(-1);
}
static void Main(string[] args)
{
ThreadPool.SetMaxThreads(5, 5);
for (int x = 0; x < 30; x++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(DoSomething), x);
}
Console.Read();
}
答案 0 :(得分:18)
ThreadPool.SetMaxThreads(5, 5)
表示活动线程数为5(如果你有超过5个cpu核心),并不意味着ThreadPool只能创建5个线程。 ThreadPool最大线程数= CPU Core * 250。
在Thread.Sleep
之后,线程处于非活动状态,因此不会影响其他线程的执行。
答案 1 :(得分:4)
但是我对ThreadPool工作方式的理解不正确, 因为如果它是正确的,下面的代码只打印数字 0-4,而不是0-29。
是的,您的假设非常正确。
由于你已经在ThreadPool中排队了30个作业,并且Jobs将为InfiniteTime休眠,它们永远不会完成,ThreadPool类将等待一定的时间间隔来创建新线程,但不会超过最大线程数。 / p>
Console.Read()使您的后台线程保持活动状态。
许多应用程序创建花费大量时间的线程 睡眠状态,等待事件发生。其他线程可能 进入睡眠状态只是为了周期性地唤醒以进行轮询 更改或更新状态信息。线程池使您可以使用 通过为应用程序提供池来提高线程效率 由系统管理的工作线程。一个线程监视 排队到线程池的几个等待操作的状态。当一个 等待操作完成,来自线程池的工作线程 执行相应的回调函数。
当所有线程池线程都已分配给任务时,该线程 池不会立即开始创建新的空闲线程。避免 不必要地为线程分配堆栈空间,它会创建新的空闲 线程间隔。间隔目前是半秒钟, 虽然它可能会在.NET Framework的未来版本中发生变化。
托管线程池中的线程是后台线程。那 是的,他们的IsBackground属性是真的。这意味着一个 毕竟ThreadPool线程不会保持应用程序运行 前台线程已经退出。
答案 2 :(得分:2)
可能是Thread.Sleep(-1)没有按预期执行。
参数Int32: 线程被阻止的毫秒数。指定零(0)以指示应该挂起此线程以允许其他等待线程执行。指定无限以无限期地阻止该线程。
http://msdn.microsoft.com/en-us/library/d00bd51t.aspx
您应该查看任务,http://msdn.microsoft.com/en-us/library/dd235608.aspx将其视为Threadpool 2.0
答案 3 :(得分:0)
通常,ThreadPool会创建一些等于CPU核心数的线程。创建更多线程没有必要,因为核心一次只能处理一个线程。但是,当排队到ThreadPool的任务执行时间超过0.5秒时,ThreadPool会创建一个额外的线程来处理队列中的剩余任务。因此,如果将大量繁重的任务排入ThreadPool,它将创建许多其他线程来模拟多任务并以“并行”方式执行所有任务。但总执行时间与没有额外线程的情况相同,而且,甚至更少,因为创建线程的操作非常繁重。这就是为什么ThreadPool被推荐用于小任务,以避免创建额外的线程,实际上没有任何优势。
您可以在Albahari's文章中阅读有关ThreadPool的更多信息。实际上,他有很多关于线程的文章。