6

也许我没有正确理解......所有并行类问题:(

但是从我现在阅读的内容来看,我了解到,当我使用 Parallel 时,我实际上会调动 threadPool 中存在的所有线程来执行某些任务/任务。

例如

  var arrayStrings = new string[1000];
  Parallel.ForEach<string>(arrayStrings, someString =>
  {
       DoSomething(someString);
  });

因此,在这种情况下,Parallel.ForEach 正在为“DoSomething”任务/任务调动 threadPool 中存在的所有线程。

但是调用 Parallel.ForEach 会创建任何新线程吗?

很明显,不会有 1000 个新线程。但是让我们假设有 1000 个新线程,在某些情况下 threadPool 释放它持有的所有线程,在这种情况下...... Parallel.ForEach 将创建任何新线程?

4

4 回答 4

11

简短的回答:Parallel.ForEach()没有“调动所有的线程”。任何安排一些工作ThreadPoolParallel.ForEach()确实如此)的操作都可能导致在池中创建新线程。

长答案:要正确理解这一点,您需要知道三个抽象级别是如何工作的Parallel.ForEach()TaskSchedulerThreadPool

  1. Parallel.ForEach()(和Parallel.For())将他们的工作安排在TaskScheduler. 如果您没有明确指定调度程序,则将使用当前调度程序。

    Parallel.ForEach()在几个Tasks 之间拆分工作。每个都Task将处理输入序列的一部分,完成后,如果有可用的部分,它将请求另一部分,依此类推。

    TaskParallel.ForEach()创建多少个s?尽可能多的TaskScheduler让它运行​​。这样做的方式是每个Task在开始执行时首先将自身的副本排入队列(除非这样做会违反MaxDegreeOfParallelism,如果您设置它)。这样,实际的并发级别就达到了TaskScheduler.

    此外,如果支持它,第一个Task实际上将在当前线程上执行TaskScheduler(这是使用 完成的RunSynchronously())。

  2. 默认值TaskScheduler只是简单地将每个Task加入ThreadPool队列。(实际上,如果Task从 another开始 a 会更复杂Task,但这在这里无关紧要。)其他TaskSchedulers 可以做完全不同的事情,其中​​一些(如TaskScheduler.FromCurrentSynchronizationContext())完全不适合与 一起使用Parallel.ForEach()

  3. ThreadPool使用相当复杂的算法来确定在任何给定时间应该运行多少线程。但这里最重要的是调度新工作项导致创建新线程(尽管不一定立即)。并且因为有了Parallel.ForEach(),总会有一些项目排队等待执行,完全取决于内部算法ThreadPool来决定线程的数量。

总而言之,几乎不可能决定 a 将使用多少线程Parallel.ForEach(),因为它取决于许多变量。两种极端都是可能的:循环将在当前线程上完全同步运行,并且每个项目都将在其自己的新创建线程上运行。

但一般来说,应该接近最佳效率,您可能不必担心所有这些细节。

于 2012-06-01T17:15:42.567 回答
1

Parallel.Foreach 不会创建新线程,也不会“调动所有线程”。它使用线程池中有限数量的线程并将任务提交给它们以进行并行执行。在当前实现中,默认设置是每个内核使用一个线程。

于 2012-06-01T12:23:49.117 回答
1

我认为你有这个错误的方式。从并行编程模式中,您会看到 Parallel.ForEach 只是真正的语法糖。

Parallel.ForEach 在很大程度上归结为这样的东西,

for (int p = 0; p < arrayStrings.Count(); p++)
{
    ThreadPool.QueueUserWorkItem(DoSomething(arrayStrings[p]);
}

ThreadPool 负责调度。如果您有兴趣,有一些关于 ThreadPool 的调度程序如何在某种程度上表现的优秀文章,但这与 TPL 无关。

于 2012-06-01T12:29:08.070 回答
0

Parallel 根本不处理线程——它将 TASKS 调度到任务框架。然后有一个调度程序,默认调度程序进入线程池。这将尝试找到大量线程(在 4.5 中比在 4.0 中更好),并且线程池可能会慢慢启动新线程。

但这不是parallel.foreach 的功能;)

Parallel.ForEach 将创建任何新线程???

它永远不会。正如我所说 - 它有 1000 个 foreach,然后它将 10.000 个任务排队,Point。任务工厂调度程序将执行它被编程做的事情((你可以替换它)。通常,默认 - 是的,慢慢地新线程会在合理的情况下出现。

于 2012-06-01T12:27:58.663 回答