Python 3.8 multiprocessing: TypeError: cannot pickle 'weakref' object
Python 3.8 multiprocessing: TypeError: cannot pickle 'weakref' object
我们正在尝试使用 multiprocessing
模块执行这段代码:
import multiprocessing as mp
ctx = mp.get_context("spawn")
(child, pipe) = ctx.Pipe(duplex=True)
job_process = ctx.Process(
name="my_job",
target=job_func,
args=(
child,
server_info,
manager,
job_config,
config_file,
),
)
job_process.start()
并且我们 运行 在 Python 3.8 中出现了以下错误,在 Python 3.6 中没有看到:
Traceback (most recent call last):
File "path/to/venv/lib/python3.8/site-packages/path/to/file.py", line 137, in includeme
job_process.start()
File "/usr/lib/python3.8/multiprocessing/process.py", line 121, in start
self._popen = self._Popen(self)
File "/usr/lib/python3.8/multiprocessing/context.py", line 284, in _Popen
return Popen(process_obj)
File "/usr/lib/python3.8/multiprocessing/popen_spawn_posix.py", line 32, in __init__
super().__init__(process_obj)
File "/usr/lib/python3.8/multiprocessing/popen_fork.py", line 19, in __init__
self._launch(process_obj)
File "/usr/lib/python3.8/multiprocessing/popen_spawn_posix.py", line 47, in _launch
reduction.dump(process_obj, fp)
File "/usr/lib/python3.8/multiprocessing/reduction.py", line 63, in dump
ForkingPickler(file, protocol).dump(obj)
TypeError: cannot pickle 'weakref' object
进程的启动方式或提供的参数是否需要更改或检查?任何方向表示赞赏!
这个问题可能是您应用程序中一个更大错误的 side-effect。 You must use import guards when using multiprocessing
in 'spawn'
mode,不这样做会发生一些奇怪的事情。特别是:
在 spawn 模式下完成的 fork-emulation 将尝试序列化一些主模块的状态,以便传输到 child 进程以类似地初始化 child; multiprocessing.Process
itself is not picklable as of Python 3.7(虽然有一个待修复的补丁),所以你绝对不想把它放在任何可能被腌制的地方。
通过不使用守卫,child 进程对主模块的导入完成 所有 主模块所做的事情,包括启动一个child(它本身会启动 child,依此类推,无穷无尽)。
这两个问题都应该通过使用 import guard 并将所有内容放入 guard 中调用的 main
函数来解决:
import multiprocessing as mp
# Wrapping in function avoids implicit dependencies on mutable global state
def main():
ctx = mp.get_context("spawn")
(child, pipe) = ctx.Pipe(duplex=True)
job_process = ctx.Process(
name="my_job",
target=job_func,
args=(
child,
server_info,
manager,
job_config,
config_file,
),
)
job_process.start()
# Guard ensures only the parent process tries to actually run main()
if __name__ == '__main__':
main()
我们正在尝试使用 multiprocessing
模块执行这段代码:
import multiprocessing as mp
ctx = mp.get_context("spawn")
(child, pipe) = ctx.Pipe(duplex=True)
job_process = ctx.Process(
name="my_job",
target=job_func,
args=(
child,
server_info,
manager,
job_config,
config_file,
),
)
job_process.start()
并且我们 运行 在 Python 3.8 中出现了以下错误,在 Python 3.6 中没有看到:
Traceback (most recent call last):
File "path/to/venv/lib/python3.8/site-packages/path/to/file.py", line 137, in includeme
job_process.start()
File "/usr/lib/python3.8/multiprocessing/process.py", line 121, in start
self._popen = self._Popen(self)
File "/usr/lib/python3.8/multiprocessing/context.py", line 284, in _Popen
return Popen(process_obj)
File "/usr/lib/python3.8/multiprocessing/popen_spawn_posix.py", line 32, in __init__
super().__init__(process_obj)
File "/usr/lib/python3.8/multiprocessing/popen_fork.py", line 19, in __init__
self._launch(process_obj)
File "/usr/lib/python3.8/multiprocessing/popen_spawn_posix.py", line 47, in _launch
reduction.dump(process_obj, fp)
File "/usr/lib/python3.8/multiprocessing/reduction.py", line 63, in dump
ForkingPickler(file, protocol).dump(obj)
TypeError: cannot pickle 'weakref' object
进程的启动方式或提供的参数是否需要更改或检查?任何方向表示赞赏!
这个问题可能是您应用程序中一个更大错误的 side-effect。 You must use import guards when using multiprocessing
in 'spawn'
mode,不这样做会发生一些奇怪的事情。特别是:
在 spawn 模式下完成的 fork-emulation 将尝试序列化一些主模块的状态,以便传输到 child 进程以类似地初始化 child;
multiprocessing.Process
itself is not picklable as of Python 3.7(虽然有一个待修复的补丁),所以你绝对不想把它放在任何可能被腌制的地方。通过不使用守卫,child 进程对主模块的导入完成 所有 主模块所做的事情,包括启动一个child(它本身会启动 child,依此类推,无穷无尽)。
这两个问题都应该通过使用 import guard 并将所有内容放入 guard 中调用的 main
函数来解决:
import multiprocessing as mp
# Wrapping in function avoids implicit dependencies on mutable global state
def main():
ctx = mp.get_context("spawn")
(child, pipe) = ctx.Pipe(duplex=True)
job_process = ctx.Process(
name="my_job",
target=job_func,
args=(
child,
server_info,
manager,
job_config,
config_file,
),
)
job_process.start()
# Guard ensures only the parent process tries to actually run main()
if __name__ == '__main__':
main()