PLINQ AsParallel ().ForAll () доступ к ресурсу
Предположим, что у меня есть некоторое число Particle
s в пространстве X,Y, и я хочу нормализовать их все так, чтобы средние 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
их, потому что они не являются объектами, но я не уверен, что я хотел бы в любом случае, потому что замок не довольно дорого?3 ответа:
Вы можете обойти необходимость блокировки (или атомарных операций) с помощью обычного механизма параллельного LINQ:
Поскольку суммирование чисел является операцией O (N), я был бы крайне удивлен, если бы эта часть заняла сколько-нибудь значительную часть времени.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 });