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

Cet*_*ert 18 c# parallel-processing synchronization locking

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

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

Kir*_*ril 34

我喜欢打死马!:)

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

Interlocked.Increment(ref count);
Run Code Online (Sandbox Code Playgroud)

但正如其他人所指出的那样:如果你在里面做,Parallel.ForEach那么你可能做错了什么.

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

更新:

ConcurrentDictionary如果您的密钥是URI值,那么您似乎是安全的TAnswer.只要您不尝试使用计数来引用集合中的元素,我就不会发现问题.

最后...

如果你需要一个计数器,那么使用Parallel.For循环...它可以安全地为你增加计数器.


小智 9

以这种方式使用 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));
});
Run Code Online (Sandbox Code Playgroud)


Que*_*rgo 8

Parallel.Foreach 附带了一个额外的重载,当您只想计算循环内的内容时,它非常适合这种场景。

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

您可以在循环体中注入线程本地计数变量并像往常一样递增/递减它。这样,您就不会在每个循环周期中进行 InterLocked 调用。相反,在每个并行任务结束时只有一个 Interlocked.Add 调用来汇总总计数。

请注意,使用此方法时,不应totalCount在循环体内使用。如果您的问题需要从循环体内访问totalCount,您必须使用InterLocked.Incerment 方法,如其他答案中所述。


Dav*_*ton 5

使用Interlocked.Increment

我不会在并行 foreach增加内容(当然,除非您使用 Interlocked.Increment 或其他一些锁定机制)。那不是它的目的。并行 foreach 应该仅与在共享状态下不会产生副作用的操作一起运行。在并行 foreach 中增加一个值将导致您很可能试图避免的问题。

  • 跟踪相当长的运行时间(分钟)的进度怎么样?我需要这样做是为了向客户反馈,以便他们可以衡量等待时间并查看进度。 (8认同)
  • 我也需要报告完成百分比。因此,如果我有 10,000 次迭代,我想跟踪完成百分比并为每增加 1% 发送一条消息。因此,当迭代 100 完成时,我需要检测到这一点。 (4认同)