如何在parallel.foreach循环范围之外增加一个整数值?什么是同步访问并行循环外对象的最轻的方法?
var count = 0;
Parallel.ForEach(collection, item =>
{
action(item);
// increment count??
}
答案 0 :(得分:32)
我喜欢打死马! :)
从多个线程增加计数的“最轻”方法是:
Interlocked.Increment(ref count);
但正如其他人所指出的那样:如果你在Parallel.ForEach
内进行,那么你可能做错了。
我怀疑由于某种原因你正在使用ForEach
但是你需要一个你正在处理的项目的索引(它永远不会与Parallel.ForEach
一起使用)。我接近了吗?你为什么需要数?你想做什么样的VooDoo魔术?
如果您的密钥为ConcurrentDictionary
且值为URI
,则TAnswer
似乎是安全的。只要您不尝试使用计数来引用集合中的元素,我就不会发现问题。
如果你需要一个计数器,那么使用Parallel.For
循环......它可以安全地为你增加计数器。
答案 1 :(得分:3)
使用Interlocked.Increment
。
我不会在里面添加并行foreach(当然,除非你使用的是Interlocked.Increment或其他一些锁定机制)。这不是它的用途。并行foreach只能在共享状态下不会产生副作用的情况下运行。在并行foreach中增加一个值会导致你很可能试图避免的问题。
答案 2 :(得分:3)
Parallel.Foreach带有一个额外的overload,当您只想计算循环中的事物时,它完全适合这种情况。
int totalCount = 0;
Parallel.ForEach(files, () => 0, (file, loopState, localCount) =>
{
if(ProcessFile(file))
localCount++;
return localCount;
}, localCount => Interlocked.Add(ref totalCount, localCount));
Console.WriteLine($"Processed {totalCount}/{files.Length} files.");
您可以向循环主体中注入线程局部计数varialble,并照常对其进行增减。这样,您就不会在每个循环周期中都有一个InterLocked调用。相反,每个并行Task的末尾只有一个Interlocked.Add调用,总计totalCount。
请注意,使用此方法时,不应在循环体内使用totalCount
。如果您的问题需要从循环体内访问totalCount,则必须使用其他答案中所述的InterLocked.Incerment方法。
答案 3 :(得分:0)
以这种方式使用Interlocked.Increment方法。
int count = 0;
Parallel.ForEach(users, (u) =>
{
var currentCount = Interlocked.Increment(ref count);
Log(String.Format("Step {0} of {1}", currentCount, users.Count));
});