什么是使用ThreadPool的正确方法?

如果我对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(); } 

ThreadPool.SetMaxThreads(5, 5)

表示活动线程的数量是5(如果你有超过5个cpu核心),并不意味着ThreadPool只能创建5个线程。 ThreadPool最大线程数= CPU Core * 250。

Thread.Sleep之后,线程处于非活动状态,因此不会影响其他线程的执行。

但是我对ThreadPool工作方式的理解是不正确的,因为如果它是正确的,下面的代码只打印数字0-4而不是0-29。

是的,你的假设是非常正确的。

由于你在ThreadPool中排队了30个作业,并且Jobs将为InfiniteTimehibernate,它们永远不会完成,ThreadPool类将等待一定的时间间隔来创建新线程,但不会超过最大线程数。

注意

Console.Read()使您的后台线程保持活动状态。

用品

  • 如何使用ThreadPool
  • 使用ThreadPool

来自MSDN

许多应用程序创建的线程在hibernate状态下花费大量时间,等待事件发生。 其他线程可能进入hibernate状态仅被定期唤醒以轮询更改或更新状态信息。 线程池使您可以通过为应用程序提供由系统管理的工作线程池来更有效地使用线程。 一个线程监视排队到线程池的几个等待操作的状态。 当等待操作完成时,来自线程池的工作线程执行相应的回调函数。


当所有线程池线程都已分配给任务时,线程池不会立即开始创建新的空闲线程。 为避免不必要地为线程分配堆栈空间,它会间隔创建新的空闲线程。 该间隔目前是半秒,尽管它可能会在.NET Framework的未来版本中发生变化。


托管线程池中的线程是后台线程。 也就是说,它们的IsBackground属性是真的。 这意味着在所有前台线程退出后,ThreadPool线程不会保持应用程序运行。

可能是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

通常,ThreadPool创建的线程数等于CPU核心数。 创建更multithreading没有必要,因为核心一次只能处理一个线程。 但是,当排队到ThreadPool的任务执行时间超过0.5秒时,ThreadPool会创建一个额外的线程来处理队列中的剩余任务。 因此,如果将大量繁重的任务排入ThreadPool,它将创建许多其他线程来模拟多任务并以“并行”方式执行所有任务。 但总执行时间与没有额外线程的情况相同,而且,由于创建线程的操作非常繁重,因此它会更少。 这就是为什么ThreadPool被推荐用于小任务的原因,以避免创建实际上没有带来任何优势的额外线程。

您可以在Albahari的文章中阅读有关ThreadPool的更多信息。 实际上,他有很多关于线程的文章。