PLINQ AsParallel().ForAll()访问资源

Ozz*_*zah 3 c# linq multithreading plinq

假设我Particle在X,Y空间中有多个s,并且我想将它们全部归一化,使得平均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;
  }
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,性能也不错,因为它是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;
  });
}
Run Code Online (Sandbox Code Playgroud)

我不确定这里的表现,但我认为它会更好.问题是,粒子都是随机跳动的.我只能假设+=上的操作avgX,并avgY在相互竞争,即使他们是相当原子了.

我能做些什么来解决它吗?我不能lock他们,因为他们不是对象,但我不确定我是否还想要,因为锁定不是很贵?

Mik*_*ley 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 });
Run Code Online (Sandbox Code Playgroud)

由于对数字进行求和是一个O(N)运算,如果这部分占用了大部分时间,我会感到非常惊讶.