我正在编写一个 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()
Region
Start()
queued
true
此代码大约需要 7 秒。这慢了 70 倍。我知道在设置线程、查找空闲线程等方面会产生一些开销。但我仍然希望我至少会获得某种性能提升。
我究竟做错了什么?