3

X、Y 空間に多数のParticles があり、平均 X と Y が 0 になるようにすべてを正規化するとします。

シリアル実装:

public void Normalise()
{
  double avgX = 0.0;
  double avgY = 0.0;

  foreach (Particle p in Particles)
  {
    avgX += p.X;
    avgY += p.Y;
  }

  avgX /= (double)Particles.Count;
  avgY /= (double)Particles.Count;

  foreach (Particle p in Particles)
  {
    p.X -= avgX;
    p.Y -= avgY;
  }
}

これは機能し、O(n) であるためパフォーマンスは悪くありませんが、「恥ずかしいほど並列」です。私の PLINQ 実装を見てください。

public void PNormalise()
{
  double avgX = 0.0;
  double avgY = 0.0;

  Particles.AsParallel().ForAll(p =>
  {
    avgX += p.X;
    avgY += p.Y;
  });

  avgX /= (double)Particles.Count;
  avgY /= (double)Particles.Count;

  Particles.AsParallel().ForAll(p =>
  {
    p.X -= avgX;
    p.Y -= avgY;
  });
}

ここでのパフォーマンスについてはよくわかりませんが、それよりも優れていると思います。問題は、パーティクルがすべてランダムに飛び回っていることです。+=と の操作は、すでにかなりアトミックになっていますが、互いに競合しているavgXとしか思えません。avgY

それを修正するためにできることはありますか?それらはオブジェクトではないのでできませんlockが、ロックはかなり高価ではないので、とにかくやりたいかどうかわかりませんか?

4

3 に答える 3

5

Parallel LINQ の通常の機構を使用して、ロック (またはアトミック操作) の必要性を回避できます。

var avgX = Particles.AsParallel().Average(p => p.X);
var avgY = Particles.AsParallel().Average(p => p.Y);

Particles.AsParallel().ForAll(p => { p.X -= avgX; p.Y -= avgY });

数値の合計は O(N) 操作であるため、この部分にかなりの時間がかかっていたら非常に驚きます。

于 2012-11-19T01:13:21.937 に答える
1

使用する

Particles.AsParallel().ForAll(p =>
{
    Interlocked.Add(avgX, p.X);
    Interlocked.Add(avgY, p.Y);
}

スレッドセーフなアトミック加算を行います。詳細については、Interlocked Classのドキュメントを参照してください。

于 2012-11-19T01:09:11.780 に答える
0

実際には、この O(n)-Algorithm を並列化しても、パフォーマンスはそれほど向上しません。これは、計算命令とほぼ同じ量のメモリ アクセスがあるためです。

于 2012-11-19T01:18:50.407 に答える