Python多进程,在循环中多次使用池后,在第一次迭代后卡住

7

我有以下情况,我在一个循环中创建池,如下所示(我知道这不是非常优雅,但我必须为选取原因而这样做)。假设pathos.multiprocessing等同于Python的multiprocessing库(因为它与一些细节相关,对于此问题不重要)。 我要执行以下代码:

self.pool = pathos.multiprocessing.ProcessingPool(number_processes)


for i in range(5):


    all_responses = self.pool.map(wrapper_singlerun, range(self.no_of_restarts))

    pool._clear()

现在我面临的问题是:循环成功地运行了第一次迭代。然而,在第二次迭代中,算法突然停止了(没有完成pool.map操作)。我怀疑产生了僵尸进程,或者进程被某种方式切换了。下面是到目前为止我所尝试过的所有方法。

for i in range(5):

    pool = pathos.multiprocessing.ProcessingPool(number_processes)

    all_responses = self.pool.map(wrapper_singlerun, range(self.no_of_restarts))

    pool._clear()

    gc.collect()

    for p in multiprocessing.active_children():
        p.terminate()
        gc.collect()

    print("We have so many active children: ", multiprocessing.active_children()) # Returns []

以上代码在我的Mac上运行得非常好。然而,当我将其上传到具有以下规格的群集时,我会遇到它在第一次迭代后卡住的错误:

DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04 LTS"

这是pathos的多进程库文件。


2
嗨,我是pathos的作者。pathos.multiprocessing提供了一个增强版的Pool,体现在两个方面:(1)更好的序列化方式,(2)更好的初始化方法。如果你只是想要更好的序列化方式,我建议你使用pathos.pools._ProcessPool,它具有与multiprocessing完全相同的接口和规范,但序列化方式更好。如果你还在寻找pathos的其他特性,那么你应该知道,pathos池会一直保留,除非显式地销毁。你需要在上面使用的池上执行pool._clearpool.restart来杀死(或重新启动)池。 - Mike McKerns
1
pathos.multiprocessing 中的接口已被弃用,推荐使用 pathos.pools.ProcessPool 接口。该池应该有一个 _clear 和一个 restart 方法。请注意,这是与 pathos.multiprocessing.ProcessPoolpathos.multiprocessing.ProcessingPool 相同的对象...我将它们保留下来以保持向后兼容性。 - Mike McKerns
1
你没有提供其他人可以运行的代码,也没有展示出现错误的情况,因此很难调试你所看到的问题。你能做到吗?目前来看,很难确定你想要做什么。 - Mike McKerns
1
如果是这种情况,您应该通过限制池中的进程数量,并在循环中使用clear来关闭每个Pool来测试该理论。这将限制活动进程的数量。您可以尝试使用ProcessPool(1)或类似的东西。 - Mike McKerns
1
@DaveTheAl,你解决了挂起的问题吗?我认为我遇到了同样的问题。 - wmcnally
显示剩余9条评论
1个回答

1
我假设您正在尝试通过某个函数调用它,这不是使用它的正确方式。
您需要将其包装在中:
if __name__ == '__main__':
    for i in range(5):

         pool = pathos.multiprocessing.Pool(number_processes)

         all_responses = pool.map(wrapper_singlerun, 

range(self.no_of_restarts))

如果不这样做,它将继续创建自身的副本,并将其放入堆栈中,最终填满堆栈并阻塞一切。它在Mac上运行的原因是它有fork,而Windows没有。

1.) 那么区别在于__name__ == "main"吗?不幸的是,我无法应用它,因为我的脚本仅仅是另一个库的模块,该库控制着我的函数如何执行。 2.) 它无法运行的另一个平台不是Windows,而是Ubuntu(在最后标记)。 - DaveTheAl
你的主脚本,也就是你首先调用的脚本,应该被包含在一个 if name == 'main' 子句中。 - Raf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接