Interlocked.Decrement(i)是否适用于Parallel.ForEach()?

Jer*_*xon 2 c# parallel-processing multithreading

在过去我做过这样的事情:

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();
}
Run Code Online (Sandbox Code Playgroud)

和平行我做这样的事情:

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();
});
Run Code Online (Sandbox Code Playgroud)

我真正的问题是:Interlocked.Decrement()在这里是否正确?

Chr*_*ain 5

Parallel.ForEach将阻塞直到所有项都被处理 - 这里正确的做法似乎是在调用Parallel.ForEach之后立即从调用者调用RaiseAllDoneEvent():

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

换句话说,根本不需要倒计时(或跟踪要处理的项目数).如果您希望并行操作不阻止,可以将其转换为一堆任务:

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

在这种情况下,你将开始一个外部任务来旋转,然后等待一堆任务(每个项目一个),然后最终提升所有完成的事件.这些都不会阻止原始呼叫者.