環境
- Python 3.8.6
- Xubuntu 18.04
問題
multiprocessing.pool.Pool
を使って、並列実行しています。
並列実行しているcube_for_row
関数内で、さらに並列実行したら、「AssertionError: daemonic processes are not allowed to have children」が発生しました。
from typing import List
import multiprocessing
def cube(value: float) -> float:
return value * value * value
def cube_for_row(row: List[float]) -> List[float]:
with multiprocessing.Pool() as pool:
return pool.map(cube, row)
def cube_for_matrix(matrix: List[List[float]], is_parallel:bool) -> List[List[float]]:
if is_parallel:
with multiprocessing.Pool() as pool:
return pool.map(cube_for_row, matrix)
else:
return [cube_for_row(row) for row in matrix]
def main():
matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
result1 = cube_for_matrix(matrix, False)
print(result1)
# OK
result2 = cube_for_matrix(matrix, True)
print(result2)
# NG
multiprocessing.pool.RemoteTraceback:
"""
Traceback (most recent call last):
File "/home/vagrant/.pyenv/versions/3.8.6/lib/python3.8/multiprocessing/pool.py", line 125, in worker
result = (True, func(*args, **kwds))
File "/home/vagrant/.pyenv/versions/3.8.6/lib/python3.8/multiprocessing/pool.py", line 48, in mapstar
return list(map(*args))
File "/home/vagrant/Downloads/run.py", line 8, in cube_for_row
with multiprocessing.Pool() as p:
File "/home/vagrant/.pyenv/versions/3.8.6/lib/python3.8/multiprocessing/context.py", line 119, in Pool
return Pool(processes, initializer, initargs, maxtasksperchild,
File "/home/vagrant/.pyenv/versions/3.8.6/lib/python3.8/multiprocessing/pool.py", line 212, in __init__
self._repopulate_pool()
File "/home/vagrant/.pyenv/versions/3.8.6/lib/python3.8/multiprocessing/pool.py", line 303, in _repopulate_pool
return self._repopulate_pool_static(self._ctx, self.Process,
File "/home/vagrant/.pyenv/versions/3.8.6/lib/python3.8/multiprocessing/pool.py", line 326, in _repopulate_pool_static
w.start()
File "/home/vagrant/.pyenv/versions/3.8.6/lib/python3.8/multiprocessing/process.py", line 118, in start
assert not _current_process._config.get('daemon'), \
AssertionError: daemonic processes are not allowed to have children
"""
原因
エラーメッセージは「デーモンプロセスは子プロセスを持てない」と言っています。
multiprocessing.pool.Pool
に渡している関数は、デーモンプロセスで実行されているようです。
multiprocessing.Process.daemon のドキュメントをには、「デーモンプロセスは子プロセスを作成できない」と記載されています。
デーモンプロセスであるかのフラグであり、ブール値です。この属性は start() が呼び出される前に設定されている必要があります。
初期値は作成するプロセスから継承します。
あるプロセスが終了するとき、そのプロセスはその子プロセスであるデーモンプロセスすべてを終了させようとします。
デーモンプロセスは子プロセスを作成できないことに注意してください。もし作成できてしまうと、そのデーモンプロセスの親プロセスが終了したときにデーモンプロセスの子プロセスが孤児になってしまう場合があるからです。さらに言えば、デーモンプロセスはUnix デーモンやサービスでは なく 通常のプロセスであり、非デーモンプロセスが終了すると終了されます (そして join されません)。
暫定的な解決方法1
「AssertionError」なので無視することもできます。
$ python -O main.py
[[1, 8, 27, 64], [125, 216, 343, 512], [729, 1000, 1331, 1728]]
ただ無視すると、ゾンビプロセスが生まれてしまうようです。
暫定的な解決方法2
デーモンプロセスの場合は並列処理しないようにします。
def cube_for_row(row: List[float]) -> List[float]:
"""並列実行できるなら並列実行する"""
process = multiprocessing.current_process()
if process.daemon:
return [cube(v) for v in row]
else:
with multiprocessing.Pool() as pool:
return pool.map(cube, row)