Pat*_*ick 13 python multiprocessing
在windows和linux上运行时,以下代码具有不同的输出(均使用python2.7)
'''import_mock.py'''
to_mock = None
Run Code Online (Sandbox Code Playgroud)
'''test.py'''
import import_mock
from multiprocessing import Process
class A(object):
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
def __getstate__(self):
print '__getstate__'
return { 'a': self.a, 'b': self.b,
'c':0 }
def func():
import_mock.to_mock = 1
a = A()
return a
def func1(a):
print a.a, a.b, a.c
print import_mock.to_mock
if __name__ == '__main__':
a = func()
p = Process(target=func1, args=(a,))
p.start()
p.join()
Run Code Online (Sandbox Code Playgroud)
在Windows上,输出是:
__getstate__
1 2 0
None
Run Code Online (Sandbox Code Playgroud)
这是我的预期
在linux上,它是:
1 2 3
1
Run Code Online (Sandbox Code Playgroud)
哪个不克隆全局对象和传递的args.
我的问题是他们为什么表现不同?如何让linux代码与windows one相同?
Blc*_*ght 19
在Linux(和其他类Unix操作系统)上,Python的multiprocessing模块fork()用于创建新的子进程,有效地继承父进程的内存状态的副本.这意味着解释并不需要咸菜正在作为传递的对象Process的args,因为子进程将已经有他们在正常的形式提供.
fork()但是,Windows没有系统调用,因此multiprocessing模块需要做更多的工作才能使子生成过程正常工作.在fork()基于实施来到第一,和非分叉Windows实现后来.
值得注意的是,Python开发人员经常觉得,根据您运行Python的平台,创建子进程的程度有点不同.因此,在Python 3.4中,添加了一个新系统,允许您选择您希望使用的启动方法.选项是"fork","forkserver"和"spawn".该"fork"方法仍然是类Unix系统的默认设置(它是早期Python版本中唯一的实现).该"spawn"方法是Windows上的默认(且唯一)选项,但现在也可以在类Unix系统上使用.该"forkserver"方法是两者之间的混合(并且仅在某些类Unix系统上可用).您可以阅读有关文档中方法之间差异的更多信息.
Tim*_*ers 13
添加到@ Blckknght的答案:在Windows上,每个进程"从头开始"导入原始模块,而在Unix-y系统上,只有主进程运行整个模块,而所有其他进程看到当时存在的任何进程fork()用于创建新流程(不,你不是在称fork()自己 - multiprocessing内部会在创建新流程时调用它).
详细地说,为您的import_mock:
在所有平台上,主进程调用func(),设置import_mock.to_mock为1.
在Unix-y平台上,这就是所有新进程看到的内容:在此fork()之后发生,因此1是所有新进程继承的状态.
在Windows上,所有新进程都"从头开始"运行整个模块.所以他们每个人都进口自己的全新版本import_mock.只有主进程调用func(),因此只有主进程看到to_mock更改为1.所有其他进程都看到新None状态.
这都是预期的,第二次实际上很容易理解;-)
传递的a内容更微妙,因为它更多地取决于multiprocessing实现细节.实现可能已经选择从一开始就在所有平台上挑选参数,但事实并非如此,现在改变而不破坏某些平台上的东西为时已晚.
由于写时复制fork()语义,没有必要Process()在Unix-y系统上挑选参数,因此实现从未这样做过.但是,没有fork()它就必须在Windows上腌制它们 - 所以实现就是这样.
在Python 3.4之前,它允许你spawn在所有平台上强制"Windows实现"(),没有机械方法来避免可能的跨平台意外.
但在实践中,我很少被这个困扰. 据了解,例如,多处理可能在很大程度上取决于酸洗,我完全不知道在哪里附近玩腌菜.你遇到"问题"传递一个A()实例的唯一原因是你正在玩泡菜技巧(通过覆盖默认值__getstate__()).