为什么这个线程代码运行得慢得多?

时间:2012-11-14 01:51:02

标签: c# multithreading

我正在编写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是一个4的数组,就我的CPU而言。它开始是4x null。对于每个区域,我遍历所有4个Thread对象(可能是null)。当我找到nullIsAlive的{​​{1}}时,我会将Index()的{​​{1}}和Region排队。我将Start()设置为queued,以便我可以判断该区域已开始编制索引。

此代码大约需要7秒钟。这比你慢了70倍。我知道设置线程,找到一个空闲的线程等有一些开销,但我仍然期望我至少会获得某种性能提升。

我做错了什么?

1 个答案:

答案 0 :(得分:3)

为什么不试试PLINQ?

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

PLINQ对我来说通常是超快的,并且它会根据你的环境进行缩放。如果它不应该是Parallel,它会做单线程。

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

 Regions.AsParallel().Cast<Region>().ForAll(x=>x.Index());