0

我正在编写一个 N-Body 模拟,为了简化计算,我将整个空间划分为多个大小一致的区域。

对于每个物体,我计算同一区域中所有其他物体的力,对于其他区域,我将质量和距离汇总在一起,因此要做的工作更少。

我有一个List<Region>Region定义public void Index()了在这次迭代中总质量的总和。

我的Space.Tick()函数有两种变体:

public void Tick()
{
  foreach (Region r in Regions)
    r.Index();
}

这非常快。对于 20x20x20 = 8000 个区域,每个区域有 100 个物体 = 总共 800000 个物体,只需大约 0.1 秒即可完成此操作。CPU 图表显示我的四核利用率为 25%,这正是我所期望的。

现在我编写这个多线程变体:

public void Tick()
{
  Thread[] threads = new Thread[Environment.ProcessorCount];

  foreach (Region r in Regions)
    while (true)
    {
      bool queued = false;

      for (int i = 0; i < threads.Length; i++)
        if (threads[i] == null || !threads[i].IsAlive)
        {
          Region s = r;
          threads[i] = new Thread(s.Index);
          threads[i].Start();
          queued = true;
          break;
        }

      if (queued)
        break;
    }
}

所以一个快速的解释,以防它不明显:threads在我的 CPU 的情况下是一个 4 的数组。它开始是 4x null。对于每个区域,我循环遍历所有 4 个Thread对象(可能是null)。当我找到一个要么null是要么不是的,IsAlive我就排队。我设置为以便我可以知道该区域已开始编制索引。Index()RegionStart()queuedtrue

此代码大约需要 7 秒。这慢了 70 倍。我知道在设置线程、查找空闲线程等方面会产生一些开销。但我仍然希望我至少会获得某种性能提升。

我究竟做错了什么?

4

1 回答 1

3

为什么不试试 PLINQ?

Regions.AsParallel().ForAll(x=>x.Index());

PLINQ 通常对我来说超级快,并且它的扩展取决于您的环境。如果它不应该是并行的,它会执行单线程。

所以,如果你必须让一个多维数组进入函数,你可以这样做:

 Regions.AsParallel().Cast<Region>().ForAll(x=>x.Index());
于 2012-11-14T02:18:53.813 回答