如何做正确的Parallel.ForEach,锁定和进度报告 [英] How to do proper Parallel.ForEach, locking and progress reporting

查看:259
本文介绍了如何做正确的Parallel.ForEach,锁定和进度报告的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实施 Parallel.ForEach 模式,跟踪进展,但我没有关于锁的东西。下面的例子计数到1000时, = THREADCOUNT 1 ,但不能当经纬> 1.什么是正确的办法做到这一点?

 类节目
{
静态无效的主要()
{
变种进度=新进展();
VAR IDS = Enumerable.Range(1,10000);
VAR THREADCOUNT = 2;

Parallel.ForEach(IDS,新ParallelOptions {MaxDegreeOfParallelism = THREADCOUNT},ID => {progress.CurrentCount ++;});

Console.WriteLine(线程:{0},次数:{1},经纬,progress.CurrentCount);
Console.ReadKey();
}
}

内部类进步
{
私有对象_lock =新的对象();
私人诠释_currentCount;
公众诠释CURRENTCOUNT
{
得到
{
锁(_lock)
{
返回_currentCount;
}
}

{
锁(_lock)
{
_currentCount =价值;
}
}
}
}


解决方案

通常的问题,呼吁像计数++ 从多个线程(它们共享计数变量)是这一系列事件可能发生:




  1. 线程A读计数

  2. 线程b读取计数的值。

  3. 线程A增加它的本地副本。

  4. 线程b增加它的本地副本。

  5. 线程A写入递增值回计数

  6. 线程b写入递增值回计数



这方式,由线程A所写的值由线程b覆盖,所以价值实际递增一次。



您的代码将围绕操作1锁,2( GET )和5,6(设置),但什么也不做,以防止事件的问题的顺序。



您需要做的是要锁定整个操作,这样当线程A是递增的价值,线程b不能在所有访问:

 锁(progressLock)
{
progress.CurrentCount ++;
}

如果你知道你只需要递增,您可以在创建方法进度封装了这一点。


I'm trying to implement the Parallel.ForEach pattern and track progress, but I'm missing something regarding locking. The following example counts to 1000 when the threadCount = 1, but not when the threadCount > 1. What is the correct way to do this?

class Program
{
   static void Main()
   {
      var progress = new Progress();
      var ids = Enumerable.Range(1, 10000);
      var threadCount = 2;

      Parallel.ForEach(ids, new ParallelOptions { MaxDegreeOfParallelism = threadCount }, id => { progress.CurrentCount++; });

      Console.WriteLine("Threads: {0}, Count: {1}", threadCount, progress.CurrentCount);
      Console.ReadKey();
   }
}

internal class Progress
{
   private Object _lock = new Object();
   private int _currentCount;
   public int CurrentCount
   {
      get
      {
         lock (_lock)
         {
            return _currentCount;
         }
      }
      set
      {
         lock (_lock)
         {
            _currentCount = value;
         }
      }
   }
}

解决方案

The usual problem with calling something like count++ from multiple threads (which share the count variable) is that this sequence of events can happen:

  1. Thread A reads the value of count.
  2. Thread B reads the value of count.
  3. Thread A increments its local copy.
  4. Thread B increments its local copy.
  5. Thread A writes the incremented value back to count.
  6. Thread B writes the incremented value back to count.

This way, the value written by thread A is overwritten by thread B, so the value is actually incremented only once.

Your code adds locks around operations 1, 2 (get) and 5, 6 (set), but that does nothing to prevent the problematic sequence of events.

What you need to do is to lock the whole operation, so that while thread A is incrementing the value, thread B can't access it at all:

lock (progressLock)
{
    progress.CurrentCount++;
}

If you know that you will only need incrementing, you could create a method on Progress that encapsulates this.

这篇关于如何做正确的Parallel.ForEach,锁定和进度报告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆