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他们,因为他们不是对象,但我不确定我是否还想要,因为锁定不是很贵?
您可以通过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)运算,如果这部分占用了大部分时间,我会感到非常惊讶.