2012-06-01 64 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