池生成无限多的工作进程

时间:2013-03-01 20:34:35

标签: python threadpool python-multithreading

我正在使用networkx(网络分析库)进行一些缓慢的计算,我正在尝试使用Pool worker来使其更快一些。计算是独立的,因此应该相对简单地并行化它们。

def computeInfoPooled(G,num_list):
    pool=Pool(processes=4)

    def f(k):
        curr_stat={}
        curr_stat[k]=slow_function(k,G)
        return curr_stat

    result = pool.map(f,num_list)

    return result

现在,我在控制台中运行了以下内容:

computed_result=computeInfoPooled(G)

我希望这段代码可以创建4个进程,并在不同进程中使用num_list的每个项目(一个数字)调用f。如果num_list包含4个以上的数字(在我的情况下大约是300个),那么它将同时运行4并将其余数据排队,直到其中一个池化工作完成。

当我运行我的代码时发生的事情是许多python.exe被生成(或分叉,不确定发生了什么)并且它似乎创建了无限多个进程,因此我不得不拔掉我的机器。

任何想法我做错了什么以及如何解决它?

2 个答案:

答案 0 :(得分:1)

在Windows上,您需要

if __name__ == '__main__':
    computed_result = computeInfoPooled(G)

使您的脚本无需启动叉炸弹就可导入。 (请阅读标题为“安全导入主模块”的部分in the docs

另请注意,在Windows上,您可能无法使用交互式解释器中的多处理模块。 请参阅top of the docs附近的警告:

  

此程序包中的功能要求 main 模块   可由儿童进口。编程指南中对此进行了介绍   但是值得指出这里。这意味着一些例子,   例如多处理.Pool示例将不起作用   互动口译员。 (我的重点。)

而是将脚本保存到文件中,例如script.py并从命令行运行它:

python script.py

此外,您需要pool.map的参数可以选择。 函数f需要在模块级别定义(不在computeInfoPooled内部以便可以选择:

def f(k):
    curr_stat = slow_function(k, G)
    return k, curr_stat


def computeInfoPooled(G, num_list):
    pool = Pool(processes=4)
    result = pool.map(f, num_list)
    return dict(result)

if __name__ == '__main__':
    computed_result = computeInfoPooled(G)

顺便说一下,如果f返回一个字典,那么pool.map(f, ...)将返回一个字典列表。我不确定这是你想要的,特别是因为每个dict只有一个键值对。

相反,如果您让f返回一个(键,值)元组,那么pool.map(f, ...)将返回一个元组列表,然后您可以将其转换为带有dict(result)的字典。

答案 1 :(得分:0)

Windows编程指南下的文档对此进行了解释。

根据您的平台,每个流程可能必须启动一个全新的解释器并import您的模块才能启动f函数。 (在Windows上,总是必须这样做。)当import模块运行时,所有顶级代码都会运行,其中包含行computed_result=computeInfoPooled(G),它会创建一个全新的4个进程池等等。

你可以像处理任何其他情况一样解决这个问题,你希望同一个文件既可作为模块导入又可作为脚本运行:

def computeInfoPooled(G,num_list):
    pool=Pool(processes=4)

    def f(k):
        curr_stat={}
        curr_stat[k]=slow_function(k,G)
        return curr_stat

    result = pool.map(f,num_list)

    return result

if __name__ == '__main__':
    computed_result=computeInfoPooled(G)

从您的编辑和评论中,您似乎期望从交互式解释器调用computeInfoPooled(G)将解决该问题。相同的链接文档部分详细解释了为什么不起作用,Introduction顶部的一个重要说明直接说:

  

此程序包中的功能要求子项可以导入 main 模块。这在编程指南中有所涉及,但值得在此指出。这意味着一些示例,例如multiprocessing.Pool示例在交互式解释器中不起作用。

如果您想了解为什么会这样,您需要阅读链接的文档(您还需要了解importpicklemultiprocessing的方式所有的工作)。