返回大对象时,Python3 多重处理不确定地挂起终止

naf*_*fur 5 python python-multiprocessing

我使用 python 多处理的方式需要将相对较大的对象返回到主线程。我的例子在这里https://pastebin.com/xs0X9wWu(在pastebin上,因为它包含一个有点大的json blob,因为这个错误需要一个大对象)主要代码如下:

def generate_mutations(original):
    for node in original:
        yield original

def check(task):
    return task

if __name__ == "__main__":
    logger = log_to_stderr()
    logger.setLevel(logging.DEBUG)

    while True:
        with Pool(2) as pool:
            for result in pool.imap(check, generate_mutations(DATA)):
            #for result in map(check, generate_mutations(DATA)):
                print("Stopping")
                break
            print("Loop is done")
        print("Processing is done")
Run Code Online (Sandbox Code Playgroud)

发生的情况是,在无限循环的几次迭代之后,池将无法终止并只是挂起(我看到“循环已完成”,但没有看到“处理已完成”)。中止(Ctrl+C)给出以下跟踪(我还在多处理调试日志中添加了):

[DEBUG/MainProcess] created semlock with handle 139668948529152
[DEBUG/MainProcess] created semlock with handle 139668948525056
[DEBUG/MainProcess] created semlock with handle 139668948520960
[DEBUG/MainProcess] created semlock with handle 139668948516864
[DEBUG/MainProcess] created semlock with handle 139668948512768
[DEBUG/MainProcess] created semlock with handle 139668948508672
[DEBUG/MainProcess] added worker
[INFO/ForkPoolWorker-5] child process calling self.run()
[DEBUG/MainProcess] added worker
[INFO/ForkPoolWorker-6] child process calling self.run()
Stopping
Loop is done
[DEBUG/MainProcess] terminating pool
[DEBUG/MainProcess] finalizing pool
[DEBUG/MainProcess] helping task handler/workers to finish
[DEBUG/MainProcess] removing tasks from inqueue until task handler finished
[DEBUG/MainProcess] worker handler exiting
[DEBUG/MainProcess] task handler found thread._state != RUN
[DEBUG/MainProcess] joining worker handler
[DEBUG/MainProcess] result handler found thread._state=TERMINATE
[DEBUG/MainProcess] task handler sending sentinel to result handler
[DEBUG/MainProcess] terminating workers
[DEBUG/MainProcess] ensuring that outqueue is not full
[DEBUG/MainProcess] joining task handler
Traceback (most recent call last):
  File "mwe.py", line 23, in <module>
    print("Loop is done")
  File "/usr/lib/python3.8/multiprocessing/pool.py", line 736, in __exit__
    self.terminate()
  File "/usr/lib/python3.8/multiprocessing/pool.py", line 654, in terminate
    self._terminate()
  File "/usr/lib/python3.8/multiprocessing/util.py", line 224, in __call__
    res = self._callback(*self._args, **self._kwargs)
  File "/usr/lib/python3.8/multiprocessing/pool.py", line 721, in _terminate_pool
    result_handler.join()
  File "/usr/lib/python3.8/threading.py", line 1011, in join
    self._wait_for_tstate_lock()
  File "/usr/lib/python3.8/threading.py", line 1027, in _wait_for_tstate_lock
    elif lock.acquire(block, timeout):
KeyboardInterrupt
[INFO/MainProcess] process shutting down
[DEBUG/MainProcess] running all "atexit" finalizers with priority >= 0
[DEBUG/MainProcess] running the remaining "atexit" finalizers
Run Code Online (Sandbox Code Playgroud)

对于池的非终止,存在一些类似的问题(https://bugs.python.org/issue9205、https://bugs.python.org/issue22393、https://bugs.python.org/issue38084 ),但它们都似乎来自以意外方式终止的工作进程。这里的情况似乎并非如此。在调试过程中,我注意到如果返回的数据较小,错误似乎会变得不那么频繁。我可以使用 Python 3.8 和 3.9 在 ubuntu 上可靠地重现该问题。check

如果我使用常规map()而不是pool.imap(),似乎没有任何问题。

那么这里的问题是什么?这是一个错误吗multiprocessing?这段代码是否multiprocessing被严重滥用?我该如何解决这个问题?