【发布时间】:2010-01-12 15:15:17
【问题描述】:
有人可以列出线程生成与线程池之间的一些比较点,哪个更好?请考虑将 .NET 框架作为支持两者的参考实现。
【问题讨论】:
-
“更好”取决于您的平台
标签: multithreading
有人可以列出线程生成与线程池之间的一些比较点,哪个更好?请考虑将 .NET 框架作为支持两者的参考实现。
【问题讨论】:
标签: multithreading
线程池线程比普通线程便宜得多,它们汇集了线程所需的系统资源。但它们有许多限制可能使它们不适合:
后两个约束是线程池调度程序的副作用,它试图将活动线程数限制为 CPU 可用的内核数。如果您安排许多经常阻塞的长时间运行的线程,这可能会导致长时间的延迟。
许多其他线程池实现也有类似的约束,给予或接受。
【讨论】:
“池”包含可供使用的可用“线程”列表,而“生成”是指实际创建一个新线程。
“线程池”的用处在于“更低的使用时间”:避免了创建时间开销。
就“哪个更好”而言:这取决于。如果创建时间开销是一个问题,请使用线程池。这是需要执行大量“短期任务”的环境中的常见问题。
正如其他人所指出的,线程池存在“管理开销”:如果实施得当,这是最小的。例如。限制池中的线程数是微不足道的。
【讨论】:
对于“更好”的一些定义,您通常希望使用线程池。在不知道您的用例是什么的情况下,考虑使用线程池,您拥有固定数量的线程,这些线程都可以在启动时创建,也可以按需创建(但线程数不能超过池的大小)。如果提交了一个任务并且没有可用的线程,则将其放入队列中,直到有空闲的线程来处理它。
如果您为响应请求或某种其他类型的触发器而生成线程,您将面临耗尽所有资源的风险,因为没有什么可以限制创建的线程数量。
线程池的另一个好处是重用 - 相同的线程被反复使用来处理不同的任务,而不是每次都必须创建一个新线程。
正如其他人所指出的,如果您有少量任务会长时间运行,这将抵消避免频繁创建线程所带来的好处(因为无论如何您都不需要创建大量线程) .
【讨论】:
我的感觉是,你应该从根据需要创建一个线程开始......如果这个性能还可以,那么你就完成了。如果在某个时候,您检测到您需要在线程创建时降低延迟,您通常可以在不破坏任何内容的情况下放入线程池...
【讨论】:
一切都取决于您的情况。创建新线程是资源密集型和昂贵的操作。大多数非常短的异步操作(最多不到几秒)都可以使用线程池。
对于您希望在后台运行的长时间运行的操作,您通常会创建(生成)您自己的线程。 (Ab) 使用平台/运行时内置线程池进行长时间运行的操作可能会导致令人讨厌的死锁等形式。
【讨论】:
线程池通常被认为更好,因为线程是预先创建的,并根据需要使用。因此,如果您将大量线程用于相对较短的任务,则速度会快很多。这是因为它们被保存以备将来使用,不会被销毁并在以后重新创建。
相比之下,如果你只需要2-3个线程并且它们只会被创建一次,那么这样会更好。这是因为您不会从缓存现有线程以供将来使用中获益,并且您不会创建可能不会使用的额外线程。
【讨论】:
这取决于你想在另一个线程上执行什么。
对于短任务,最好使用线程池,对于长任务,最好生成一个新线程,因为它可能会使线程池无法用于其他任务。
【讨论】:
主要区别在于 ThreadPool 维护一组已启动并可供使用的线程,因为启动一个新线程在处理器方面可能代价高昂。
但是请注意,即使是 ThreadPool 也需要“生成”线程...它通常取决于工作负载 - 如果有很多工作要做,一个好的线程池会根据配置启动新线程来处理负载和系统资源。
【讨论】:
创建/生成线程所需的额外时间很少,因为线程轮询已经包含已创建的线程,可供使用。
【讨论】:
这个answer 是一个很好的总结,但以防万一,这里是维基百科的链接:
【讨论】:
对于结合从执行中获取返回值的多线程执行,或者检测线程池已完成的简单方法,可以使用 java Callables。
请参阅https://blogs.oracle.com/CoreJavaTechTips/entry/get_netbeans_6 了解更多信息。
【讨论】:
假设 C# 和 Windows 7 及更高版本...
当您使用 new Thread() 创建线程时,您创建的托管线程会在您调用 Start 时由本机操作系统线程提供支持——这是一对一的关系。重要的是要知道在任何给定时间只有一个线程在 CPU 内核上运行。
更简单的方法是调用 ThreadPool.QueueUserWorkItem(即后台线程),它本质上做同样的事情,除了那些后台线程不会永远绑定到单个本地线程。 .NET 调度程序将在单个本机线程上模拟托管线程之间的多任务处理。假设有 4 个内核,您将拥有 4 个本机线程,每个线程运行多个托管线程,由 .NET 确定。这提供了轻量级的多任务处理,因为托管线程之间的切换发生在 .NET VM 中,而不是在内核中。从用户模式到内核模式的交叉存在一些开销,而 .NET 调度程序将这种交叉最小化。
需要注意的是,繁重的多任务处理可能会受益于精心设计的多线程框架中的纯本机操作系统线程。但是,性能优势并没有那么多。
使用 ThreadPool,只需确保最小工作线程数足够高,否则 ThreadPool.QueueUserWorkItem 将比 new Thread() 慢。在一个循环 512 次调用 new Thread() 的基准测试中,ThreadPool.QueueUserWorkItem 在默认最小值的情况下尘埃落定。但是,首先将最小工作线程数设置为 512,在此测试中,使 new Thread() 和 ThreadPool.QueueUserWorkItem 的性能相似。
设置高工作线程数的一个好处是 new Task()(或 Task.Factory.StartNew)的执行也与 new Thread() 和 ThreadPool.QueueUserWorkItem 类似。
【讨论】: