[英]Wait Handles and the System.Threading.Tasks namespace
當我在System.Threading.Tasks
命名空間中使用Parallel.ForEach
或Parallel.For
時,是否可以假定所有線程在執行繼續之前已同步?
是否有等同於
WaitHandle.WaitAll(...);
繼續嗎
所以,如果我打電話給
Parallel.ForEach(collection, DoSomethingWithObject);
我可以確定在 ForEach
返回之前 ,對DoSomethingWithObject
每次調用已完成,還是我需要自己使用WaitHandles
?
為了擴展Phong的正確答案,Parallel.For和Parallel.ForEach在內部創建了一個所謂的ParallelXXXReplicationTask,它可以同步運行並生成X個子任務,其中X是有效的並發級別(默認為Environment.ProcessorCount)。 每個子任務都與Semphore同步,Semphore會在設置(計數為0)后釋放父任務,以確保僅在所有子任務完成(或崩潰/停止,這由同步設置確定)后,父任務的執行才會返回。 由於parentTask是同步運行的,正在等待中。 您可以確保每當返回對Parallel方法的調用時,所有迭代均已有效完成。
所有任務將在Parallel.ForEach()
返回時完成,除非專門調用Stop()
來中止並行執行。 在這種情況下,由Parallel.ForEach()
返回的ParallelLoopState
對象的.IsCompleted
屬性將為false
。
你可以在這里讀到它:
http://msdn.microsoft.com/en-us/library/dd992001.aspx
http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallelloopresult.aspx
您也可以編寫一個小型測試應用程序,其中DoSomethingWithObject()
是一個運行時間很長的操作,或者調用Thread.Sleep()
進行驗證。 執行將阻塞,直到所有線程都完成睡眠為止。
樣品:
Parallel.ForEach(Enumerable.Range(1, 8),
i =>
{
Thread.Sleep(5000);
Console.WriteLine(i + " done!");
});
Console.WriteLine("All done!");
我可以確定在ForEach返回之前,對DoSomethingWithObject的每次調用已完成,還是我需要自己使用WaitHandles?
Parallel.ForEach
是一個阻止調用。 在每次迭代完成之前,它不會返回。
是否有等效於
WaitHandle.WaitAll(...);
繼續嗎
是的,或多或少。 它實際上不會使用WaitHandle.WaitAll
因為1)效率極低,並且2)無法擴展,因為它有64個句柄限制。 有幾種非常可擴展的技術可以等待多個任務完成。 我的最愛之一是使用CountdownEvent
。 1
下面是它的工作原理。 發揮您的想象力並假裝Parallel.ForEach
被擴展為以下代碼。 2
var finished = new CountdownEvent(1);
foreach (var item in collection)
{
var capture = item;
finished.AddCount();
Task.Factory.StartNew(
() =>
{
try
{
DoSomething(capture);
}
finally
{
finished.Signal();
}
});
}
finished.Signal();
finished.Wait();
1我並不是說這是Parallel.ForEach
所使用的技術,但可能與此類似。
2實際上, Parallel.ForEach
以更為復雜的方式實現。 我只是想幫助您直觀地了解它如何等待每次迭代完成。
Parallel.ForEach()
和Parallel.For()
將阻塞,直到其所有任務結束為止,要么是因為它們成功完成,要么是因為它們被取消了。 因此,是的,所有線程在執行繼續之前都已同步。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.