2011-09-01 45 views
2

在過去,我已經做到了這一點:Interlocked.Decrement(i)適用於Parallel.ForEach()嗎?

List<Item> _Items = GetItems(); 
int _CountDown = _Items.Count; 
using (BackgroundWorker _Worker = new BackgroundWorker()) 
{ 
    _Worker.DoWork += (s, arg) => 
    { 
     DoSomething(_Items[_CountDown]); 
    }; 
    _Worker.RunWorkerCompleted += (s, arg) => 
    { 
     if (System.Threading.Interlocked.Decrement(ref _CountDown) == 0) 
      RaiseAllDoneEvent(); 
     else 
      _Worker.RunWorkerAsync(); 
    }; 
    _Worker.RunWorkerAsync(); 
} 

與並行做somethign這樣的:

List<Item> _Items = GetItems(); 
int _CountDown = _Items.Count; 
System.Threading.Tasks.Parallel.ForEach(_Items, (i) => 
{ 
    DoSomething(i); 
    if (System.Threading.Interlocked.Decrement(ref _CountDown) == 0) 
     RaiseAllDoneEvent(); 
}); 

我真正的問題是:是Interlocked.Decrement()正確嗎?

回答

5

Parallel.ForEach將阻塞,直到所有的項目都processed-在這裏做正確的事情似乎是從呼出的電話RaiseAllDoneEvent()調用Parallel.ForEach後:

List<Item> _Items = GetItems(); 
System.Threading.Tasks.Parallel.ForEach(_Items, (i) => 
{ 
    DoSomething(i); 
}); 
RaiseAllDoneEvent(); 

換句話說,根本不需要倒計數(或記錄要處理的物品數量)。如果你想在並行操作不阻塞,你可以把它變成了一堆任務:

List<Item> _Items = GetItems(); 
Task.Factory.StartNew(()=> { 
     Task.WaitAll(
      _Items.Select(i => Task.Factory.StartNew(() => DoSomething(i))).ToArray() 
     ); 
    }).ContinueWith(t => RaiseAllDoneEvent()); 

在這種情況下,你會開始外任務旋轉起來,然後等待一串任務(每個項目一個),然後最終提高所有完成的事件。這些都不會阻止原來的呼叫者。

+0

是否有一個利用並行的異步選項? –

+0

Sure-Task.Factory.StartNew()。我會編輯來說明。 –

+0

對不起,一個任務神奇地已經利用並行? –