在什么情况下应使用不同的.NET线程方法?

3

我一直在研究处理多线程的.NET应用程序的不同方法,但变得有些混乱了。

新线程 -> 当仅需要一个附加线程时?

线程池 -> 当需要多个线程时。使用现有线程并将优化(基于所涉及工作的数量)留给框架更加节省成本。

任务 -> 当您需要一个额外的线程,并且恰好在使用.NET 4.0或更高版本时。这是新线程的API吗?

Parallel.for -> 当您有多个任务并希望框架根据CPU核心数为不同任务分配工作的优化时。

在MSDN上,并未说明 new Thread 方法已过时?


1
不要忘记微软的响应式框架。 - Enigmativity
1个回答

7
您对ThreadThreadPool的基本理解是基本正确的。但是,Task则更加复杂。
首先,Task仅表示异步操作。它可以在ThreadPool线程上执行(如果您是调度任务的人,则通常会使用TaskScheduler.Default),也可以在单独的非线程池线程上执行(当您指定TaskCreationOptions.LongRunning时)。它甚至可以在没有线程的情况下执行(考虑异步IO操作:http://blog.stephencleary.com/2013/11/there-is-no-thread.html)。最后,当一个Task封装多个异步操作时,它可以是以上任何一种的组合。
最终,TaskThreadThreadPool之上添加了一层抽象(在适当的情况下内部使用它们,而在调度任务时,您对此有一定程度的控制)。在三种线程方法中,Task应该是您的首选,因为它周围构建了语言支持。使用Task组合异步操作序列与使用低级别线程工具相比轻而易举。
但是,这并不意味着ThreadThreadPool是真正过时的-仅仅是它们不应该是您新开发的首选。抛开它们在使用Task时仍然由框架在内部使用的事实,想想有多少完全功能的生产代码使用了ThreadThreadPool,以及如果将其中任何一种类型标记为ObsoleteAttribute会发生什么。这将是一团糟。
当然,还有其他使用它们的原因,例如极其性能敏感的场景(我确定还有更多,但我现在想不起来了)。
使用Task调度工作时,您考虑何时使用ThreadPool或新的Thread仍然适用。这里的指南很简单:
  • 如果任务需要连续运行(例如在整个进程运行时运行的任务),建议在启动时指定TaskCreationOptions.LongRunning标志。这类似于启动新线程。
  • 如果您有一些有限的 CPU 绑定工作需要异步执行,请通过Task.Run将其推送到ThreadPool中(使用默认任务调度程序,即当前实现中的ThreadPoolTaskScheduler)。这类似于使用ThreadPool.QueueUserWorkItem(WaitCallback)
  • 如果您的任务大部分时间都在执行异步 IO,则不需要担心它在哪里执行。

Parallel

现在让我们谈谈Parallel类及其成员。首先,您有 Parallel.Invoke,它大致相当于并行启动一堆任务,然后阻塞等待它们完成。只有在处理多个阻塞操作需要并行运行时才会非常有用。如果是这种情况,并且您不想处理多个Task实例,请使用它。

Parallel.ForParallel.ForEach有些不同,主要用于对集合元素进行并行化的CPU绑定工作(由于内置的“负载均衡”方式,对于IO工作来说使用它们不是一个好主意,最终会产生太多线程,除非您限制并行度)。这些方法在概念上与ThreadThreadPoolTask有所不同,并且更接近于PLINQ。在将集合元素处理并行化导致可衡量的性能提升的情况下,使用它们通常可以代替forforeach循环。


1
美丽。谢谢。 - Kye
对于 Parrel.ForEach(),我经常在批处理时使用它们。不幸的是,大多数情况下我会读取一些配置文件,进行密集计算并写入小型结果文件。不幸的是,调度程序为此启动了无数个线程 - 解决这个问题的方法是简单地指定一个选项类并将 maxparallelism 设置为 processorcount-1。 - Christian Sauer
@ChristianSauer,这是因为您在传递给Parallel.ForEach的委托体内阻塞了异步(IO)操作,导致负载均衡器失控 - 这正是我在最后一段谈到的确切问题(您也碰巧使用了我提到的解决方法)。这在Stephen Toub的《并行编程模式》第33页中有所讨论 - 以及一个适当的修复方法,即在涉及IO绑定工作时避免使用Parallel.ForEach,而是使用批处理的Task,最终实现更有效的资源使用和更好的可伸缩性。 - Kirill Shlenskiy

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