对于 Task.Factory.StartNew 和 Parallel.Invoke,线程可以 运行 在不同的处理器或内核上

Threads can run on different processors or cores for both Task.Factory.StartNew and Parallel.Invoke

我希望阐明我对 .NET 多线程的理解,特别是哪些 .NET 方法创建的线程可能会在 multi-processor/core 系统中的不同处理器或内核上同时执行。

在 .NET TPL 框架中,您可以使用方法 Parallel.Invoke 或 Task.Factory.StartNew 来实现某种并行性。

我的理解是,在这两种情况下,.NET 都会创建新任务(在 Parallel.Invoke 的幕后),然后 .NET 环境将其分配给幕后的托管线程,然后将其分配给线程, CPU 可能会根据工作负载分配给不同的内核或处理器。这两种方法的主要区别在于语义——Parallel.Invoke 执行多个任务并等待它们完成; Task.Factory.StartNew 在后台启动一个新任务。在这两种情况下,实际工作可能在不同的内核或处理器上完成。根据 Task Parallel Library (TPL).

我有一个同事确信只有 Parallel.Invoke 方法允许线程在不同的 cores/processors 上执行,并且 Task.Factory.StartNew 启动一个新线程但是那个线程将只安排在一个 core/processor - 所以实际上并没有提供并行性。

我找不到任何文档或文章明确说明是否属于这种情况。我的同事向我推荐了我正在查看的相同文章,例如 Task-based Asynchronous Programming,我认为这验证了我的理解,但我的同事认为验证了他的理解。

文档有时使用术语 "parallel processing" 来引用 Parallel.Invoke 和 "asynchronous tasks" 来引用 "Task.Factory.StartNew",但据我了解,同样的事情发生在关于分配给多个 processors/cores.

的背景

任何人都可以帮助澄清情况,如果可能的话,链接到 documentation/articles。

我知道这听起来像是在寻求解决与同事争论的方法,但我真的很想澄清我是否理解正确。

其实很容易回答。

Task.Run()

Queues the specified work to run on the ThreadPool ....

Task Parallel Library

... In addition, the TPL handles the partitioning of the work, the scheduling of threads on the ThreadPool, ....

使用同一个ThreadPool,ThreadPool如何判断任务的类型来限制CPU?它们要么在所有处理器上都运行,要么在单个处理器上都运行。

加分项:

这引出了一个问题,ThreadPool 多核感知吗?

答案出人意料,不在乎。 ThreadPool asks the operating system(就像任何使用 new Thread() 的 c# 应用程序一样)对于线程,它实际上是 OS 的责任。我认为现在已经很清楚了,所有的抽象甚至暗示 C# 可以 默认 限制线程的使用方式是一个非常荒谬的断言。 (是的,你可以 运行 在你想要的任何核心上创建一个线程等等,但这不是线程池 默认 的工作方式)。

我强烈推荐阅读 StartNew is Dangerous... TLDR?使用 Task.Run().

尽管操作系统有时会提供 "processor affinity,",但这是一种边缘情况,它的使用(或可用性)非常罕见。据我所知,.NET 没有使用这些东西。

您的基础假设必须始终是:"a runnable thread/process will run where it damn well pleases," 并且它可能随时从一个 CPU 资源切换到另一个。 .NET 框架在很多方面为您提供了很多东西 "nicer",但底层的调度决策仍然由主机操作系统完全做出。