使用线程池的正确方法是什么
本文关键字:方法 是什么 线程 | 更新日期: 2023-09-27 17:56:02
如果我对 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 个线程。线程池最大线程数 = CPU 核心数 * 250。
Thread.Sleep
后,线程处于非活动状态,因此不会影响其他线程的执行。
但是我对线程池工作方式的理解是不正确的,因为如果正确,下面的代码将只打印数字0-4,而不是 0-29。
是的,你的假设是非常正确的。
由于您在 ThreadPool 中排队了30 个作业,并且这些作业将休眠无限时间,因此它们永远不会完成,因此 ThreadPool 类将等待一定的时间间隔来创建新线程,但不会超过最大线程数。
注意
Console.Read() 使您的后台线程保持活动状态。
文章
- 如何使用线程池
- 使用 ThreadPool
来自 MSDN
<小时 />许多应用程序创建的线程花费大量时间在睡眠状态,等待事件发生。其他线程可能会进入睡眠状态,只是为了定期被唤醒以轮询更改或更新状态信息。线程池使您能够使用通过为应用程序提供由系统管理的工作线程。一个线程监视排队到线程池的多个等待操作的状态。当一个等待操作完成,线程池中的工作线程执行相应的回调函数。
<小时 />将所有线程池线程分配给任务后,线程池不会立即开始创建新的空闲线程。要避免不必要地为线程分配堆栈空间,它会创建新的空闲线程间隔。间隔目前为半秒,尽管它可能会在 .NET Framework 的未来版本中更改。
托管线程池中的线程是后台线程。那是,它们的 IsBackground 属性为真。这意味着线程池线程毕竟不会保持应用程序运行前台线程已退出。
Thread.Sleep(-1) 没有按照您的期望执行操作。
参数 Int32:线程被阻止的毫秒数。指定零 (0) 以指示应挂起此线程以允许执行其他等待线程。指定"无限"可无限期地阻止线程。
http://msdn.microsoft.com/en-us/library/d00bd51t.aspx
您应该研究任务,http://msdn.microsoft.com/en-us/library/dd235608.aspx 将其视为线程池 2.0
通常,ThreadPool 创建的线程数等于 CPU 内核数。没有必要创建更多线程,因为内核一次只能处理一个线程。但是,当排队到线程池的任务需要 0.5 秒以上的时间来执行时,线程池会创建一个额外的线程来处理队列中的剩余任务。因此,如果您将大量繁重的任务排队到 ThreadPool,它将创建大量额外的线程来模拟多任务并"并行"执行所有任务。但是总执行时间将与没有其他线程的时间相同,而且,它会更少,因为创建线程是相当繁重的操作。这就是为什么建议将 ThreadPool 用于小任务,以避免创建实际上不会带来任何优势的额外线程。
您可以在Albahari的文章中阅读有关ThreadPool的更多信息。实际上,他有一套关于线程的文章。