为什么分叉进程 Linux 时子进程会继承 `sys.modules` 而在 Macos 中却没有
Why does the child process inherit `sys.modules` when forking processes Linux but not in Macos
在不同的平台上使用多处理时,sys.modules
的处理方式似乎有所不同。如果您在 Linux 上修改 sys.modules
字典并生成一个子进程,该进程似乎继承了字典,但在 Macos 中会为 sys.modules
创建一个新对象。这是因为多处理的工作方式不是 OS 不可知的吗?
这是因为 Linux 在创建子进程时使用 fork()
而 Mac 的做法不同吗?
例如,如果我尝试这个片段:
import multiprocessing
import sys
import time
from types import ModuleType
def worker():
# print the id of the dict
print('worker', id(sys.modules), 'foo' in sys.modules)
def main():
# modify the sys.modules dict
sys.modules['foo'] = ModuleType('foo')
# print the id of the dict
print('main', id(sys.modules), 'foo' in sys.modules)
p = multiprocessing.Process(target=worker, daemon=True)
p.start()
time.sleep(0.1)
if __name__ == '__main__':
main()
我得到这些结果:
Linux (x86_64, python 3.10.1)
main 139897509461248 True
worker 139897509461248 True
Macos(M1 ARM,python 3.10.1)
main 4307217856 True
worker 4334595520 False
对于上下文:我正在尝试仅使用 stdlib(ala Celery)构建任务队列。但是,我找不到将腌制函数传递给工作进程的惯用方法,但在大多数情况下,我发现在取消序列化函数时属性查找失败(在序列化可调用对象时,pickle 仅存储名称和模块,并且已加载在运行时反序列化)。
我正在尝试的解决方法是在序列化函数时更改函数的 __module__
属性,并将其添加到动态创建的模块中。这似乎修复了属性查找错误,但感觉像是一个糟糕的 hack。
在 MacOS 上,新的 multi-processing 进程默认生成而不是分叉。这效率较低,并且包含 re-import 个包和模块。
来自docs:
Changed in version 3.8: On macOS, the spawn start method is now the
default. The fork start method should be considered unsafe as it can
lead to crashes of the subprocess. See bpo-33725.
您可以尝试 multiprocessing.set_start_method()
,风险自负。
在不同的平台上使用多处理时,sys.modules
的处理方式似乎有所不同。如果您在 Linux 上修改 sys.modules
字典并生成一个子进程,该进程似乎继承了字典,但在 Macos 中会为 sys.modules
创建一个新对象。这是因为多处理的工作方式不是 OS 不可知的吗?
这是因为 Linux 在创建子进程时使用 fork()
而 Mac 的做法不同吗?
例如,如果我尝试这个片段:
import multiprocessing
import sys
import time
from types import ModuleType
def worker():
# print the id of the dict
print('worker', id(sys.modules), 'foo' in sys.modules)
def main():
# modify the sys.modules dict
sys.modules['foo'] = ModuleType('foo')
# print the id of the dict
print('main', id(sys.modules), 'foo' in sys.modules)
p = multiprocessing.Process(target=worker, daemon=True)
p.start()
time.sleep(0.1)
if __name__ == '__main__':
main()
我得到这些结果:
Linux (x86_64, python 3.10.1)
main 139897509461248 True
worker 139897509461248 True
Macos(M1 ARM,python 3.10.1)
main 4307217856 True
worker 4334595520 False
对于上下文:我正在尝试仅使用 stdlib(ala Celery)构建任务队列。但是,我找不到将腌制函数传递给工作进程的惯用方法,但在大多数情况下,我发现在取消序列化函数时属性查找失败(在序列化可调用对象时,pickle 仅存储名称和模块,并且已加载在运行时反序列化)。
我正在尝试的解决方法是在序列化函数时更改函数的 __module__
属性,并将其添加到动态创建的模块中。这似乎修复了属性查找错误,但感觉像是一个糟糕的 hack。
在 MacOS 上,新的 multi-processing 进程默认生成而不是分叉。这效率较低,并且包含 re-import 个包和模块。
来自docs:
Changed in version 3.8: On macOS, the spawn start method is now the default. The fork start method should be considered unsafe as it can lead to crashes of the subprocess. See bpo-33725.
您可以尝试 multiprocessing.set_start_method()
,风险自负。