ThreadPool.QueueUserWorkItem与Task.Factory.StartNew


79

下面有什么区别

ThreadPool.QueueUserWorkItem

Task.Factory.StartNew

如果对于长时间运行的任务,上述代码被调用了500次,是否意味着所有线程池线程都将被占用?

还是TPL(第二个选项)足够聪明,只占用少于或等于处理器数量的线程?

Answers:


93

如果要使用TPL启动长时间运行的任务,则应指定TaskCreationOptions.LongRunning,这意味着它不会在线程池上调度它。(编辑:如评论中所述,这特定于调度程序的决定,并不是硬性的快速保证,但我希望任何明智的生产调度程序都可以避免在线程池上调度长期运行的任务。)

您绝对不应该自己在线程池上安排大量长时间运行的任务。我相信这些天线程池的默认大小非常大(因为它经常被这种方式滥用),但从根本上讲,不应这样使用它。

与实际运行时间相比,线程池的目的是避免任务在创建新线程时遭受重大打击。如果任务将长时间运行,则创建新线程的影响无论如何都会相对较小-并且您不希望最终可能耗尽线程池线程。(现在不太可能了,但是我确实在.NET的早期版本中体验过。)

就我个人而言,如果我可以选择的话,我绝对会以TaskAPI相当不错为由来使用TPL,但务必告诉TPL您希望任务能够长时间运行。

编辑:如评论中所述,另请参阅PFX团队的博客文章,有关在TPL和线程池之间进行选择

最后,我将重申CLR团队的ThreadPool开发人员已经说过的话:

Task is now the preferred way to queue work to the thread pool.

编辑:同样从评论中,不要忘记TPL允许您使用自定义调度程序,如果您确实想要...


4
我对TaskCreationOptions.LongRunning总是避免线程池的硬性快速规则保持警惕。它似乎更多是指令,而不是实现保证。我是否以此为基础?
Marc

1
@Marc:好吧,这取决于调度程序-但是在线程池IMO上显式调度长时间运行的任务将是一个非常疯狂的调度程序。
乔恩·斯基特


@Brad:谢谢,将在我的答案中添加一个链接。
乔恩·斯基特

1
我还要补充一点,TPL允许您指定自己的调度程序,包括允许您控制自己的并发性的自定义调度程序:msdn.microsoft.com/en-us/library/ee789351.aspx
Chris Shain 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.