使用线程池和普通线程有什么区别?

15

我在 Stack Overflow 上阅读随机问题和答案时看到了这个问题:

C#,IAsyncResult 和线程池

问题是 X 方法是使用线程池还是使用普通线程。

使用线程池和普通线程有什么区别?

4个回答

21

线程池通常适用于短时间运行的任务。它有一个限制,即它是应用程序范围内的有限资源(每 CPU 25 个线程),并且有许多内部类使用线程池,因此如果执行大量长时间运行的任务,则会用尽所有线程。

对于长时间运行的任务,最好使用手动创建的线程,并将其背景属性设置为 true。

注意:在 .NET Framework 2.0 版本中,Thread.CurrentPrincipal 属性值会传播到使用 QueueUserWorkItem 方法排队的工作线程。在早期版本中,主体信息不传播。

何时不使用线程池线程

以下情况下,创建和管理自己的线程而不使用线程池线程是合适的:

  • 您需要前台线程。

  • 您需要一个线程具有特定的优先级。

  • 您有导致线程长时间阻塞的任务。线程池有一个最大线程数,因此大量被阻塞的线程池线程可能会防止任务启动。

  • 您需要将线程放入单线程公寓。所有线程池线程都在多线程公寓中。

  • 您需要将稳定的标识与线程关联,或将线程专用于任务。

一个重要区别是:线程池线程上的未处理异常会终止进程;但有三个例外情况:

  • 在线程池线程中抛出 ThreadAbortException,因为调用了 Abort

  • 在线程池线程中抛出 AppDomainUnloadedException,因为应用程序域正在卸载。

  • 公共语言运行时或宿主进程终止线程。

一些好的参考资料包括:

托管线程池

C#中的线程

在.NET Framework中编程使用线程池

更新:回应评论。可以使用 GetAvailableThreads 方法来确定线程池中实际线程数。 ThreadPool.GetMaxThreads 是另一种不同的数量。它是请求排队之前池中允许的最大线程数,而不是当前池中实际存在的线程数。


一些长时间运行的任务可能需要将background属性设置为false,以确保您的线程在应用程序关闭之前完成其工作(当然这并不能保证它会完成,但至少它不会在正常情况下关闭)。 - JoshBerke
@Fredrik Mörk: 那听起来像是一个打字错误。每个核心是25 - Mitch Wheat
1
@Mitch:我刚刚通过调用ThreadPool.GetMaxThreads进行了检查,它返回500(在双核机器上)。 - Fredrik Mörk
@Mitch:GetAvailableThreads返回线程池当前空闲并可供使用的线程数;GetMaxThreads和GetAvailableThreads之间的差异将告诉您当前正在使用多少工作线程。如果您没有在任何线程池线程中进行任何正在进行的工作,则它们应返回相同的值。 - Fredrik Mörk
1
@Mitch Wheat @Josh 这不是一种类型,这个数字取决于框架版本的不同。 - Kev Hunter
显示剩余3条评论

7
区别不在于线程本身,因为它们的行为是相同的,区别在于谁管理线程的生命周期以及你如何使用它们。
.NET中的线程池是一组线程,它会在需要时增加或减少线程数量。当你将任务提交给线程池处理时,它会确定是否需要启动新线程或重用现有线程。你不必显式地创建线程。
这很好,但缺点是线程池中可用线程数量是有限的。因此,如果你提交了一个长时间运行的任务,这可能会对你的应用程序产生负面影响,因为你可能正在使用其他东西想要使用的线程池线程。
请参阅关于线程池的文章

3

线程池持有一定数量的线程,这些线程可以随时使用,这可能会消除创建新线程的成本,而创建普通线程时就是发生这种情况。


0
线程池创建线程并将工作分配给空闲线程。这样可以避免为每个工作项创建和处理线程,因为创建和处理线程是相对昂贵的操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接