在parallel.foreach范围之外增加计数值

时间:2010-03-06 23:15:58

标签: c# synchronization locking parallel-processing

如何在parallel.foreach循环范围之外增加一个整数值?什么是同步访问并行循环外对象的最轻的方法?

var count = 0;
Parallel.ForEach(collection, item =>
{
  action(item);
  // increment count??
}

4 个答案:

答案 0 :(得分:32)

我喜欢打死马! :)

从多个线程增加计数的“最轻”方法是:

Interlocked.Increment(ref count);

但正如其他人所指出的那样:如果你在Parallel.ForEach内进行,那么你可能做错了。

我怀疑由于某种原因你正在使用ForEach但是你需要一个你正在处理的项目的索引(它永远不会与Parallel.ForEach一起使用)。我接近了吗?你为什么需要数?你想做什么样的VooDoo魔术?

UPDATE:

如果您的密钥为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));
});