2012-10-08 70 views
10

我正在調查For循環中的Parallelism Break。Parallel.For和Break()誤解?

閱讀thisthis後,我仍然有一個問題:

我期望此代碼:

Parallel.For(0, 10, (i,state) => 
    { 
       Console.WriteLine(i); if (i == 5) state.Break(); 
    } 

爲了獲得在 6號(0..6)。 不僅他沒有這樣做,但有不同的結果長度:

02351486 
013542 
0135642 

很煩人。 (這裏是地獄歇(){5}後這裏?)

所以我看了看MSDN

歇可用於向循環傳達當前迭代之後沒有其他迭代需要的話跑。 如果Break是從 並行從0到1000迭代的for循環的第100次迭代中調用的,則所有小於100的迭代仍應爲 運行,但從101到1000的迭代不是必需的。

Quesion#1:

哪些迭代?整個迭代計數器?或每個線程?我很確定它是每個線程。請批准。

問題2:

讓我們假設我們正在使用並行+範圍分區(由於元件之間沒有CPU成本變化),所以它劃分線程之間的數據。因此,如果我們有4個內核(和完善部門之間他們):

core #1 got 0..250 
core #2 got 251..500 
core #3 got 501..750 
core #4 got 751..1000 

所以core #1線程將滿足value=100和某個時候將打破。 這將是他的迭代號100。 但core #4中的線程得到了更多的量子,他現在在900上。他是的方式,超越他的100'th迭代。 他沒有索引少100停! - 所以他會展示給大家。

對嗎?這就是爲什麼我的例子中有超過5個元素的原因嗎?

問題3:

如何CN我真正休息的時候(i == 5)

p.s.

我的意思是,加油!當我做Break()時,我希望循環停止。 excuctly正如我在常規For循環中所做的那樣。

回答

10

產生最多6個數字(0..6)。

問題是這個不會最多產生6個數字

會發生什麼情況是,當您用循環索引5進行循環時,會發送「break」請求。 Break()將導致循環不再處理任何值>5,但處理所有值<5

但是,任何已經啓動的大於5的值仍然會被處理。由於各種指標並行運行,因此它們不再進行排序,因此您會得到各種運行,其中某些值>5(例如您的示例中爲8)仍在執行中。

哪些迭代?整個迭代計數器?或每個線程?我很確定它是每個線程。請批准。

這是傳入Parallel.For的索引。 Break()不會阻止項目被處理,但保證所有項目最多可處理100個,但超過100個項目可能會或不會得到處理。

對嗎?這就是爲什麼我的例子中有超過5個元素的原因嗎?

是的。如果您使用的是像您所示的分區程序,只要您致電Break(),那麼超出破壞分區的項目將不再安排。但是,已完成預定的項目(即整個分區)將得到充分處理。在你的例子中,這意味着你可能總是處理所有1000個項目。

當(i == 5)時,我該如何真正地破碎?

你是 - 但是當你在平行運行時,事情會改變。這裏的實際目標是什麼?如果您只想處理前6個項目(0-5),則應在之前通過LINQ查詢或類似方法來限制項目。然後您可以在Parallel.ForParallel.ForEach中處理6個項目,而不需要Break(),而且不用擔心。

我的意思是,加油!當我做Break()時,我希望循環停止。 excactly,正如我在定期For循環中那樣。

如果您希望事情儘快停止,您應該使用Stop()而不是Break()。這不會阻止已運行的項目停止,但不會再計劃任何項目(包括枚舉中較低指數或較早指數的項目)。

+0

你的意思是_Break()會導致循環不再處理任何值,它們的INDEX> 5_ ....對吧? –

+0

@RoyiNamir是的,有點。如果項目已經安排並開始,項目仍然會被處理,但是沒有新項目會被處理。如果你在'Parallel.ForEach'中,那麼你調用Break()的枚舉中的位置將不再被調度。 –

+0

有沒有anu區別'對於foreach'關於break? –

6

如果分段是從一個用於並行循環迭代的第100次迭代調用從0到1000

循環的第100次迭代不一定是(實際上可能不是)的一個與索引99.

您的線程可以並且將以獨立的順序運行。遇到.Break()指令時,將不會開始進一步的循環迭代。具體何時發生取決於特定運行的線程調度的具體情況。

我強烈建議閱讀

Patterns of Parallel Programming

(從微軟免費的PDF)

理解設計決策和設計權衡是走進了TPL。

4

哪些迭代?整個迭代計數器?或每個線程?

關閉預定(或尚未安排)的所有迭代。

請記住,委託可能運行不規則,不能保證迭代i == 5將是第六個執行,而這種情況在極少數情況下不太可能發生。

Q2:對嗎?

不,調度不是那麼簡單。而是將所有任務排隊,然後處理隊列。但是每個線程都使用自己的隊列,直到它們從其他線程竊取時爲止都是空的。這導致無法預測哪個線程將處理什麼代表。

如果代表足夠微不足道,它可能全部在原始調用線程上處理(沒有其他線程有機會竊取工作)。

Q3:當我(i == 5)時我怎麼真的破裂?

如果您想要線性(特定)處理,請不要同時使用。

Break方法可以支持推測執行:嘗試各種方法,並在任何一個完成時立即停止。

+0

*不要同時使用,如果你想線性(特定)處理。* ...真,但...可以確保一部分工作並行進行,工作在需要的時間點同步,然後並行完成額外的工作,直到另一個需要的同步點等等。只需要強調,您的正確聲明爲該類型的模式留下了空間。 –

+0

@EricJ。沒錯,但在這個問題中沒有證據表明這是另外兩件作品之間的一個同步點(並且「Parallel.For」往往是錯誤的起點)。相反,Q是關於「Parallel.For」不是「具有額外魔力的循環」的明顯缺乏理解。 – Richard