多处理给出断言错误:不允许守护进程有孩子

Anu*_*ush 5 python python-multiprocessing

我第一次尝试使用多处理。所以我想我会做一个非常简单的测试示例,它可以分解 100 个不同的数字。

from multiprocessing import Pool
from primefac import factorint
N = 10**30
L = range(N,N + 100)
pool = Pool()
pool.map(factorint, L)
Run Code Online (Sandbox Code Playgroud)

这给了我错误:

Traceback (most recent call last):
  File "test.py", line 8, in <module>
    pool.map(factorint, L)
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 251, in map
    return self.map_async(func, iterable, chunksize).get()
  File "/usr/lib/python2.7/multiprocessing/pool.py", line 567, in get
    raise self._value
AssertionError: daemonic processes are not allowed to have children
Run Code Online (Sandbox Code Playgroud)

我看到Python 进程池非守护进程?讨论了这个问题,但我不明白为什么它与我的简单玩具示例相关。我究竟做错了什么?

aba*_*ert 7

问题似乎是primefac使用它自己的multiprocessing.Pool. 不幸的是,当 PyPI 宕机时,我找不到模块的源代码——但我确实在 GitHub 上找到了各种分支,比如这个,它们都有multiprocessing代码。

因此,您看似简单的示例并不是那么简单——因为它正在导入和运行非简单代码。

默认情况下,所有Pool进程都是守护进程,因此您无法从另一个Pool. 通常,尝试这样做是错误的。

如果您确实想要多处理这些因素,即使其中一些因素要多处理他们自己的工作(很可能会在不添加任何并行性的情况下增加更多的争用开销),那么您只需要子类化Pool并覆盖它——如相关问题中所述你链接的

但最简单的事情就是不要multiprocessing在这里使用,如果primefac已经在有效地使用您的内核。(如果您需要准并发,在它们进来时获得答案而不是按顺序获得它们,我想您可以使用线程池来做到这一点,但我认为这里没有任何优势 - 您没有使用imap_unorderedAsyncResult在任何地方明确。)

或者,如果它大部分时间没有使用您的所有内核,仅在分解一些数字结束时为“棘手的余数”这样做,而您有 7 个内核闲置了 60% 的时间……那么您可能想完全阻止primefac使用multiprocessing。我不知道该模块是否具有用于执行此操作的公共 API。如果是这样,当然,只需使用它。如果不是……好吧,您可能必须对它的某些代码进行子类化或猴子修补,或者,最坏的情况是,猴子修补其导入的multiprocessing,这可能不值得这样做。

理想的解决方案可能会进行重构primefac,推动了“棘手剩女”的工作在你已经使用同一个池。但这可能是迄今为止最多的工作,而不是更多的好处。


附带说明一下,这不是您的问题,但是您应该对__main__顶级代码进行保护,如下所示:

from multiprocessing import Pool
from primefac import factorint

if __name__ == '__main__':
    N = 10**30
    L = range(N,N + 100)
    pool = Pool()
    pool.map(factorint, L)
Run Code Online (Sandbox Code Playgroud)

否则,当使用spawnforkserverstart 方法运行时——请注意,这spawn是 Windows 上唯一可用的方法——每个池进程将尝试创建另一个子池。所以,如果你在 Windows 上运行你的代码,你会得到同样的断言——作为一种multiprocessing保护你免受意外 forkbombing 你的系统的方法。

这在文档的“编程指南”部分中的主模块的安全导入下进行了解释multiprocessing