C# 移除联锁。并行添加。用于?

C# 移除联锁。并行添加。用于?,c#,parallel-processing,plinq,interlocked,C#,Parallel Processing,Plinq,Interlocked,我有一些代码可以使用parallel.for进行查找和计数: //...initialize _table with int values... int elements=60; int[] outerCounter=new int[elements]; Parallel.For(1, 2000, i0=> { int[] counter=new int[elements]; int nextPos0=_table[10+i0]; for(i1=i0+1; i1<1990

我有一些代码可以使用parallel.for进行查找和计数:

//...initialize _table with int values...
int elements=60;
int[] outerCounter=new int[elements];
Parallel.For(1, 2000, i0=>
{
  int[] counter=new int[elements];
  int nextPos0=_table[10+i0];
  for(i1=i0+1; i1<1990; i1++){ 
    //...here are also some additionale calculations done...  

    int nextPos1=_table[nextPos0+i1];
    counter[nextPos1]++;
  }
  //synchronize
  for(int i=0; i<elements;i++){
    Interlocked.Add(ref outerCounter[i], counter[i]);
  }
}
/…使用int值初始化\u表。。。
int元素=60;
int[]outerCounter=新的int[元素];
平行。对于(12000,i0=>
{
int[]计数器=新的int[元素];
int nextPos0=_表[10+i0];

对于(i1=i0+1;i1从我从代码中得到的信息,如果不锁定计数器[I],您将无法正确执行此操作由于所有线程都将写入outcounter中的所有值。

我基本上建议使用与Hans相同的方法,但我认为提供一些代码会很有用。下面是我可能会解决此问题的方法:

//...initialize _table with int values...
int elements=60;
List<int[]> outerCounter=new List<int[]>();
Parallel.For(1, 2000, i0=>
{
  int[] counter;
  lock(outerCounter)
  {
    if (outerCounter.Count == 0)
      counter = new int[elements];
    else
    {
      counter = outerCounter[outerCounter.Count - 1];
      outerCounter.RemoveAt(outerCounter.Count - 1);
    }
  }
  int nextPos0=_table[10+i0];
  for(i1=i0+1; i1<1990; i1++){ 
    //...here are also some additionale calculations done...  

    int nextPos1=_table[nextPos0+i1];
    counter[nextPos1]++;
  }
  lock (outerCounter)
    outerCounter.Add(counter);
});

int totalCounter = new int[elements];
Parallel.For(0, elements - 1, i =>
{
  foreach (int[] counter in outerCounter)
    totalCounter[i] += counter[i];
});
/…使用int值初始化\u表。。。
int元素=60;
List outerCounter=新列表();
平行。对于(12000,i0=>
{
int[]计数器;
锁(外部计数器)
{
if(outerCounter.Count==0)
计数器=新的整数[元素];
其他的
{
计数器=outerCounter[outerCounter.Count-1];
outerCounter.RemoveAt(outerCounter.Count-1);
}
}
int nextPos0=_表[10+i0];
对于(i1=i0+1;i1
{
foreach(外部计数器中的int[]计数器)
totalCounter[i]+=计数器[i];
});

此处的参与方迟到了一点,但如果您只增加计数器[]和outerCounter[]中的值,则可以使用重载版本的Parallel.For()
不必为每个循环创建元素的本地数组,您可以为执行创建一个本地数组(一次只能由一个线程操作) 例如:

int elements=60;
int[] outerCounter=new int[elements];

Parallel.For (1, 2000,
  () => new int[elements],                        // Initialize the local value.    
  (i0, state, counter) =>
    {
        int nextPos0=_table[10+i0];
        for(i1=i0+1; i1<1990; i1++)
        { 
            //...here are also some additionale calculations done...  
            int nextPos1=_table[nextPos0+i1];
            counter[nextPos1]++;
        }
    }

  counter =>                                    // Add the local value
    { 
        for(int i=0; i<elements;i++)
        {
            Interlocked.Add(ref outerCounter[i], counter[i]);
        }
    }
);
int元素=60;
int[]outerCounter=新的int[元素];
(2000年1月1日,
()=>newint[elements],//初始化本地值。
(i0、状态、计数器)=>
{
int nextPos0=_表[10+i0];
对于(i1=i0+1;i1//添加本地值
{ 

对于In i=0;II在一个双核上进行测试,两个版本都是相同的。在一个四元组中,你的版本是慢的5%。这个方法很有趣,应该根据条件而快一些。如果你用SpinLocks替换了监视器锁,我会很好奇,如何在四核上改变性能。例如,将1-2000替换为1到200,每次迭代10次。