过去我这样做过:
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();
}
使用并行,我会做这样的事情:
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() 这里正确吗?
最佳答案
Parallel.ForEach 将阻塞,直到处理完所有项目 - 这里正确的做法似乎是在调用 Parallel.ForEach 之后立即从调用者调用 RaiseAllDoneEvent():
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());
在这种情况下,您将启动一个外部任务来旋转,然后等待一堆任务(每个项目一个),最后引发所有完成事件。这些都不会阻止原始调用者。
关于c# - Interlocked.Decrement(i) 适合 Parallel.ForEach() 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7276603/