2012-06-01 68 views
5

也许我不明白它的权利...所有的Parallel类问题:(使用System.Threading.Tasks.Parallel在线程池中创建新线程?

但是,从我现在看书,我明白,当我使用并行其实我动员中存在的线程池的所有线程对于

例如一些任务/任务:。

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

所以Parallel.ForEach在这种情况下动员中存在的线程池的“DoSomething的”任务/任务的所有线程

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

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

+0

['Parallel.ForEach'](http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel.foreach.aspx) - “执行foreach(For Each in Visual Basic )操作,其中迭代**可以**并行运行。“ –

回答

10

简答题:Parallel.ForEach()不会“调动所有线程”。任何在ThreadPoolParallel.ForEach())上执行某些工作的操作都可能导致在该池中创建新线程。

龙答:要正确地理解这一点,你需要知道三个层次的抽象作品如何:Parallel.ForEach()TaskSchedulerThreadPool

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

    Parallel.ForEach()拆分了几个Task之间的工作。每个Task将处理输入序列的一部分,当它完成时,它将请求另一部分,如果可用的话,等等。

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

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

  2. The default TaskScheduler只是将每个Task排队到ThreadPool队列。 (其实TaskTask开始Task更复杂,但在这里没有关系。)其他TaskScheduler s可以做完全不同的事情,其中​​一些(如TaskScheduler.FromCurrentSynchronizationContext())完全不适合与Parallel.ForEach()一起使用。

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

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

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

1

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

+1

这根本不是真的。如果'Parallel.ForEach()'中的代码长时间阻塞或运行,将会使用比内核数量更多的线程。 – svick

0

并行并不根本处理线程 - 它将TASKS安排到任务框架。然后有一个调度程序,默认调度程序转到线程池。这个将尝试找到一个线程数(4.5比4.0更好),并且线程池可能会慢慢地启动新线程。

但是,这不是parallel.foreach的functoin;)

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

它永远不会。正如我所说 - 它有1000个foreach,然后它排队10.000个任务,点。任务工厂调度程序将执行它所编程的任务((可以替换它)。一般情况下,默认 - 是的,缓慢的新线程将在原因之内弹出。

+0

* n *项目集合中的'Parallel.ForEach()'通常不会创建* n *'任务',这可能效率太低。它对源集合进行分区,并创建与TaskScheduler允许其运行一样多的Task。 – svick

1

我认为你有这种错误的方式 从PATTERNS OF PARALLEL PROGRAMMING你会看到Parallel.ForEach只是真的语法糖。

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

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

线程池需要调度的照顾。有一些关于ThreadPool的调度程序如何在某种程度上表现出色的文章如果你有兴趣,但这与TPL无关。

+1

'new Thread()'将始终创建一个新线程,而不是使用线程池中的一个线程。您发布的代码将始终创建与集合中的项目一样多的线程。这绝不代表Parallel.ForEach。 –

+0

@AllonGuralnek你是正确的,更新。 –

+1

'Parallel.ForEach()'不是建立在ThreadPool之上的,它建立在TaskScheduler之上。而且,每个'Task'中的代码更聪明,所以每个项目都没有一个'Task'。另一件事是你的代码不会阻塞,但'Parallel.ForEach()'做。 – svick