你能在Python中使用多进程进行嵌套并行处理吗?

3

我对Python中的多进程编程还不太熟悉,现在我想要尝试以下内容:

import os
from multiprocessing import Pool
from random import randint

def example_function(a):

    new_numbers = [randint(1, a) for i in range(0, 50)]

    with Pool(processes=os.cpu_count()-1) as pool:
        results = pool.map(str, new_numbers)

    return results


if __name__ == '__main__':

    numbers = [randint(1, 50) for i in range(0, 50)]

    with Pool(processes=os.cpu_count()) as pool:
        results = pool.map(example_function, numbers)

    print("Final results:", results)

然而,当我运行时出现了以下错误:"AssertionError: daemonic processes are not allowed to have children"。
pool.map替换为for循环可以使其正常工作。例如,对于第二个:
results = []
for n in numbers:
    results.append(example_function(n))

然而,由于外部和内部任务都非常密集,我希望能够并行执行两者。我该怎么做?


让外部进程编排所有工作并为您启动工作进程。每当内部进程需要完成一项工作时,请与外部进程协调管理它们。 - Grismar
1个回答

3

multiprocessing.Pool创建进程时将daemon标志设置为True。根据Python Process类的文档,这可以防止在工作进程中创建子进程:

进程的守护进程标志,布尔值。必须在调用start()之前设置。
初始值从创建进程继承。 当进程退出时,它会尝试终止所有守护子进程
请注意,不允许守护进程创建子进程否则,如果父进程退出时终止了守护进程,则它会使其子进程变成孤儿。此外,这些不是Unix守护进程或服务,而是普通进程,如果非守护进程已退出,则将被终止(而不是加入)。

理论上,您可以创建自己的池,并使用自定义上下文来绕过进程创建以创建非守护进程。但是,您不应该这样做,因为如文档所述,进程的终止是不安全的。

实际上,在实践中创建池中的池不是一个好主意,因为池的每个进程都会创建另一个进程池。这导致创建了大量进程,非常低效。在某些情况下,进程的数量将太大,以至于操作系统无法创建它们(这取决于平台)。例如,在像最近的64核AMD threadripper处理器这样的多核处理器上,总进程数将为128 * 128 = 16384,这显然是不合理的。

解决此问题的通常方法是考虑任务而不是进程。任务可以添加到共享队列中,因此工作程序可以计算任务,然后通过向共享队列中添加新任务来生成新任务。据我所知,multiprocessing 管理器对设计这样的系统很有用。


好的,谢谢,这很有道理。您知道在我提供的示例中使用管理器会是什么样子吗? - MrPhilipT
我从未直接使用过它们,但Python文档中有许多示例。例如,您可以创建一个队列,并将其注册到管理器中,以便在进程中访问它们,或通过管理器端创建列表,然后在进程中将其用作堆栈(列表不适用于队列)。如果需要保护数据,还有锁定机制可供使用。这些示例非常有用,请务必阅读它们。 - Jérôme Richard

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