C# 修改基准列表时的PLINQ O(n^2)

C# 修改基准列表时的PLINQ O(n^2),c#,multithreading,linq,plinq,C#,Multithreading,Linq,Plinq,假设我有一个顺序函数: private void Process() { for (int i = 0; i < Particles.Count; i++) for (int j = 0; j < Particles.Count; j++) if (check(Particles[i], Particles[j]) { Particle newParticle = Particle.Merge(Particles[i], Parti

假设我有一个顺序函数:

private void Process()
{
  for (int i = 0; i < Particles.Count; i++)
    for (int j = 0; j < Particles.Count; j++)
      if (check(Particles[i], Particles[j])
      {
        Particle newParticle = Particle.Merge(Particles[i], Particles[j]);
        Particle p1 = Particles[i];
        Particle p2 = Particles[j];

        Particles.Remove(p1);
        Particles.Remove(p2);
        Particles.Add(newParticle);

        i = j = 0;
      }
}
我得到一个LINQ例外

有什么方法可以并行执行此n^2操作并更改列表的内容吗?

请尝试以下方法:

from p1 in Particles.AsParallel()
    let collisions = from p2 in Particles
                     where p1 != p2
                     where check(p1, p2)
                     select p2
    select Particle.Merge(p1, collisions)
其中第二个
粒子.Merge
作用于碰撞列表以生成新粒子。你会希望这里有更多的逻辑,但这会给你一个想法

基本思想是您希望以非破坏性方式创建列表的新副本。然后做任何修改并替换旧列表

您需要做的一些事情是:

  • 修改
    Particle.Merge
    对列表进行操作:
    Particle.Merge(Particle
    p、 i可数碰撞)
  • 添加一些逻辑以防止重复出现在该列表中两次

您的程序正在崩溃,因为您正在修改正在迭代的集合。不要那样做。我完全知道它为什么会抛出异常。我的问题是如何使用
aspallel()
来实现这一点,以便它/不会/抛出异常。首先,不要对所有
ForEach
使用
。使用
Select
。当可能存在竞争条件或需要改变集合结构时,应尽量避免对所有
使用
。一个更好的解决方案是并行地创建一个新的列表(做起来很便宜,您正在使用引用)并替换旧的列表。如果我有时间完成它,您可能会对我编写的递归PLINQ N体解算器感兴趣。它处理碰撞的方式与我在下面的帖子中描述的完全相同。
from p1 in Particles.AsParallel()
    let collisions = from p2 in Particles
                     where p1 != p2
                     where check(p1, p2)
                     select p2
    select Particle.Merge(p1, collisions)