通过多个进程循环进行碰撞检测

时间:2013-11-05 09:25:48

标签: python multiprocessing collision-detection

我正在使用python编写理想的气体模拟器,而现在碰撞检测是该程序中最密集的部分。目前,我只使用了我的8个核心中的一个。 (我使用的是i7 3770 @ 3.4GHz)

经过最小化的谷歌搜索后,我找到了python的多处理模块(2.7.4)。我试过了。经过一番思考,我意识到我可以真正并行运行的唯一方法就是在这里,我遍历所有粒子以检测碰撞:

for ball in self.Objects:   
        if not foo == ball:
            foo.CollideBall(ball, self.InternalTimestep)

这里foo是我正在测试所有其他人的粒子。 所以我试着这样做:

for ball in self.Objects:   
        if not foo == ball:
            p = multiprocessing.Process(target=foo.CollideBall, args=(ball, self.InternalTimestep))
            p.start()

虽然程序确实运行得更快,但它仍然只使用最大程度的1.5核心,其余的只是处于空闲状态而且它也没有检测到任何碰撞!我已经读过如果你一次创建太多的进程(超过核心数),那么你会得到一个积压(这是一个196粒子的循环),所以这可能解释了比我预期的更低的速度,但它并没有解释我仍然没有使用我所有核心的事实!

无论哪种方式都太慢了!那么有没有办法可以创建8个进程,只有在运行的进程少于8个时才创建一个新进程?这甚至会解决我的问题吗?我如何使用我的所有核心/为什么这个代码还没有?

我昨天才发现python中的多处理,所以我担心任何答案都要拼写出来。

感谢您的帮助!

--- --- EDIT

为了回应Carson,我尝试在p.start之后直接添加p.join,这会使程序放慢速度。而不是每个周期花费0.2秒,每个周期需要24秒!

2 个答案:

答案 0 :(得分:3)

据我所知,你测试一个粒子对所有其他粒子,然后依次对每个粒子进行操作。基于此,我想说你的问题是你试图优化你的代码以适用于所有核心而不试图优化你自己的代码。

相反,您可以对粒子进行分区,以便只检查彼此接近的粒子。一个可能的意思是四叉树:见http://en.wikipedia.org/wiki/Quadtree

在第二步中,您可以并行化所有内容。对于四元树,您可以手动解析最高级别,并为每个子树创建一个新进程。这样,这些过程彼此独立并且不会阻塞。我期望通过四叉树将二次加速(想想当前运行时间的平方根)和通过并行化实现进一步线性加速(除以进程数)。

抱歉,我不能用Python拼出来。

答案 1 :(得分:0)

使用工作四叉树,您可以设置一个线程池(作为一个类)并定义分配给各个线程的作业(另一个类)(如果可能,还可以从线程框架中另一个类)。在您的情况下,作业包含必须检查的四叉树节点的列表。最初,每个顶级四叉树节点(2D / 8中的4个3D节点)都驻留在自己的工作中。

因此,您最多可以拥有4个(相应的8个)线程,每个线程都会检查四叉树的独立子树。如果你需要更多线程来充分利用你的机器处理能力,你可以让线程将部分工作放回线程池,如果它们遇到许多深层子树。

为此,我将使用BFS(广度优先搜索)和作业中的四叉树节点列表。如果列表比预期的更长,我会把它的一部分放回到线程池中。数学/统计学/随机数学方面的知识有助于找到预期长度的良好参数化。

我还编写了一个四叉树实现,根据给定“世界”大小的预期对象数量并计算平均对象大小来自我参数化。

搜索开源项目d-collide。虽然它在C ++中应该有一些有用的示例代码。但是请考虑它的许可,这不是很多,因为它是BSD风格。

  

我将此添加为第二个答案,因为第一个答案是关于优化代码以实现隐含目标:更好的运行时间(尽管通过更高的效率)

第二个答案是关于实现书面目标:更强的并行化。 然而,四元树启用了第二步,但不要指望第二速度与第一步一样多。特别是当涉及到许多物体时,没有什么比优化算法更好。但是不要迷失于微观优化中:参见Cancelling a Task is throwing an exception

中的运行时讨论