多重处理产生AssertionError:守护进程不允许有子进程

时间:2018-07-23 18:34:11

标签: 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)

这给了我错误:

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

我看到Python Process Pool non-daemonic?讨论了这个问题,但我不明白为什么它与我的简单玩具示例有关。我在做什么错了?

2 个答案:

答案 0 :(得分:2)

问题似乎是primefac使用了自己的multiprocessing.Pool。不幸的是,当PyPI崩溃时,我找不到该模块的源代码,但是我确实在GitHub上找到了各种分支,例如this one,它们都具有multiprocessing代码。

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

默认情况下,所有Pool进程都是守护进程,因此您不能从另一个Pool内部创建更多子进程。通常,尝试这样做是错误的。

如果您确实想对这些因素进行多处理,即使其中一些因素要对自己的工作进行多处理(可能会增加更多争用开销而又不增加任何并行性),那么您只需将Pool子类化并覆盖如the related question that you linked所述。

但是最简单的事情是,如果multiprocessing已经在有效地使用您的内核,那就不要在这里使用primefac。 (如果您需要准并发性,而不是按顺序获取答案,我想您可以使用 thread 池来做到,但我认为这样做没有任何好处此处-您不在任何地方使用imap_unordered或显式AsyncResult。)

或者,如果大多数情况下都使用所有内核,那么在考虑到一些数字后,仅对“微不足道的剩余”这样做,而您有7个内核空闲60%的时间...那么您可能想完全禁止primefac使用multiprocessing。我不知道该模块是否具有用于执行此操作的公共API。如果是这样,当然可以使用它。如果没有,那么,您可能必须对其某些代码进行子类化或monkeypatch,或者更糟糕的是,对multiprocessing的导入进行monkeypatching,这可能是不值得的。

理想的解决方案可能是重构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)

否则,当使用spawnforkserver启动方法运行时,请注意spawn是Windows上唯一可用的方法,每个池进程将尝试创建另一个池。孩子们。因此,如果您在Windows上运行代码,您将得到相同的断言—作为multiprocessing的一种保护您免于意外破坏系统的方法。

multiprocessing文档的“编程准则”部分的safe importing of main module下对此进行了解释。

答案 1 :(得分:0)

我来这里是因为我的单元测试提高了

#Set number value
number = 2
#Check closest object
def total_num(number):
    total = 0 #declare total variable here instead.
    while number % 2 == 0 and number <=20:
        total = total + number
        number = number + 2

    print('The total is {}'.format(total)) #Modify to display the total
    return total #Do not remove this line

#Do not remove the next line
total_num(number)

这是因为我使用过AssertionError: daemonic processes are not allowed to have children 而没有使用multiprocessingclose join正确,在poolclose之后,现在一切都很好了。