InterLocked.Addを並列に削除しますか?
-
26-10-2019 - |
質問
ルックアップを行い、Parallel.forを使用してOccuranceをカウントするコードがいくつかあります。
//...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]);
}
}
このバージョンは、シーケンシャル計算よりもはるかに高速です。しかし、私は、OccuranceをInterocked.Addとしてカウントするための別のソリューションを見つけたいと思います。 Plinqがオプションであるかどうかを調査していましたが、アレイ内のNextPos1要素の出来事をカウントする方法を見つけることができませんでした。
解決
私は基本的にハンスと同じことを提案しますが、コードを提供することは有用だと思いました。これが私がおそらく問題に取り組む方法です:
//...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];
});
他のヒント
コードから得られるものから、アウトカウンター[i]をロックせずにこれを正しく行うことはできません[i]は、すべてのスレッドがアウトカウンターのすべての値に書き込まれるためです。
ここでパーティーに少し遅れていますが、カウンター[]とアウターカウンター[]の値を増やしている場合は、過負荷型バージョンのparallel.for()を使用できます。
各ループの要素のローカル配列を作成する代わりに、実行するためにローカル1つを作成できます(一度に1つのスレッドでのみ操作されます)。たとえば
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]);
}
}
);
上記のコードをテストしていませんが、それはJistです。 Interlocked.add()を呼び出す回数を大幅に削減します
詳細については、このサイトは非常に優れています。http://www.albahari.com/threading/part5.aspx
所属していません StackOverflow