使用多核处理器的python粗粒度并行化



我有一个python程序,在某个点它调用了一个外部程序(foo)。这个外部程序需要运行几次。确切的次数(num_pros)是可变的,取决于输入。因为这个外部程序是到目前为止我的Python程序中最耗时的部分,所以我想利用多核处理器来同时运行外部程序的几个实例。

我提出了以下解决方案,考虑到num_pros是先验未知的,并且解决方案应该适用于任何数量的核心。

cores=2
proc_list=[]
for i in range(0,num_pros):
    proc=Popen(['foo'], stdin=PIPE)
    proc_list.append(proc)
    if i%cores == cores-1: 
        for process in proc_list:
            process.wait()

我有两个问题:

有更好的(更有效的或python的)解决方案吗?

这段代码只在内核是真实的情况下减少了执行时间。这是硬件问题吗?或者可以使用python修复的东西?

为了澄清第二个问题,让我举一个例子。在我的笔记本电脑(运行linux)中,命令'cat/proc/cpuinfo | grep processor | wc -l'表明存在4个处理器,如果我在代码中使用cores=2,我可以在一半的时间内得到结果(如预期的那样),但是当使用cores=3或cores=4时,我得到的性能与使用cores=2时相同。我有一个英特尔核心I3(2核和4线程)因此我猜问题是只有2核是真实的(我在其他计算机/处理器中测试代码,我得到同样的结果,只有真正的核心似乎是有用的)。

我认为multiprocessing更适合您想要在python中农场工作的情况,而不是完全不同的过程。这都是关于使用fork并将内容从python进程传递到python进程,所以我认为它不适合你。

在你当前的实现中,一旦产生了最大数量的子进程,你的代码就会阻塞新的子进程的产生,直到所有当前批进程完成,因为Popen.wait()阻塞直到特定的子进程完成。

我认为你需要的是os.wait()。我做了一些非常类似的事情,保持我的subprocess.Popen实例的映射由pid映射。只要启动子进程的最大数量,然后让os.wait()告诉您其中一个进程何时完成。os.wait()将为您提供Popen实例接下来完成的任何操作的pid,您可以使用它对子进程执行任何剩余的清理。然后让代码启动下一个子流程。

简单的方法:采用n核系统,进行一些基准测试,以确定应用程序在最高效率下需要执行多少进程。它可能在N, N+1或N+2个进程(例如。对于通常的软件构建make运行,文档通常建议将-j设置为N+1)。然后,对于生产运行,只需向用户或操作系统询问物理内核(不是线程)的数量,并生成N或N+1或任何进程。

更复杂,更酷,但不一定更好的方法:如果你可以测量完成工作单元的吞吐量,你可以尝试动态调整进程的数量,甚至不需要知道/检测cpu/内核/线程的数量——如果你喜欢,就像TCP窗口大小一样。从2个进程的目标开始,当第一个结束测量吞吐量并使目标+=1(即使总数达到3个进程)。测量,冲洗,重复。只要总吞吐量不断增加,就保持递增,当总吞吐量下降时就递减。在混合中加入一些迟滞,并确保配置一个相同的上限。

关于您的笔记本示例,是的,这是一个多线程CPU,多线程将比其他工作负载更有利于某些工作负载,您的工作负载不会从中受益:)

最新更新