为什么multiprocessing.Process在Windows和Linux上对全局对象和函数参数的行为不同

时间:2016-07-07 01:11:11

标签: python multiprocessing

以下代码在Windows和Linux(都使用python2.7)上运行时有不同的输出

'''import_mock.py'''
to_mock = None
'''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()

在Windows上,输出为:

__getstate__
1 2 0
None

这是我的预期

在linux上,它是:

1 2 3
1

哪个不克隆全局对象和传递的args。

我的问题是他们的行为有何不同?如何使linux代码与windows one相同?

2 个答案:

答案 0 :(得分:18)

在Linux(和其他类Unix操作系统)上,Python的multiprocessing模块使用fork()创建新的子进程,有效地继承父进程内存状态的副本。这意味着解释器不需要挑选作为Process的{​​{1}}传递的对象,因为子进程已经以正常形式提供它们。

Windows没有args系统调用,因此fork()模块需要做更多工作才能使子生成过程正常工作。基于multiprocessing的实现首先出现,而非分叉的Windows实现则是后来的。

值得注意的是,Python开发人员经常觉得,根据您运行Python的平台,创建子进程的程度有点不同。因此,在Python 3.4中,添加了一个新系统,允许您select the start method that you would prefer to use。选项包括fork()"fork""forkserver""spawn"方法仍然是类Unix系统的默认方法(它是早期Python版本中唯一的实现)。 "fork"方法是Windows上的默认(且唯一)选项,但现在也可以在类Unix系统上使用。 "spawn"方法是两者之间的混合(并且仅在某些类Unix系统上可用)。您可以阅读有关文档中方法之间差异的更多信息。

答案 1 :(得分:12)

添加到@ Blckknght的答案:在Windows上,每个进程都从头开始导入原始模块"而在Unix-y系统上只有主进程运行整个模块,而所有其他进程流程会看到当fork()用于创建新流程时存在的任何内容(不,自己没有调用fork() - multiprocessing内部调用无论何时创建新流程。)

详情请参阅import_mock

  • 在所有平台上,主流程调用func(),将import_mock.to_mock设置为1。

  • 在Unix-y平台上,这是所有新进程看到的内容:fork()之后发生,所以1是所有新进程继承的状态。

  • 在Windows上,所有新进程都从头开始运行整个模块"#34;。因此,他们每个人都导入自己的全新版import_mock。只有主流程调用func(),因此只有主流程会将to_mock更改为1.所有其他流程都会看到新的None州。

这一切都是预期的,第二次实际上很容易理解; - )

传递a后发生的事情更微妙,因为它更多地取决于multiprocessing实施细节。实现可以从一开始就选择在所有平台上挑选参数,但它没有,现在改变而且不会破坏 some <上的东西为时已晚/ em>平台。

由于写时复制fork()语义,在Unix-y系统上挑选Process()参数并不是必要的,因此实现永远不会没有。但是,如果没有fork(),就必须在Windows上对它们进行腌制 - 因此实现方式确实如此。

在Python 3.4之前,它允许你强制执行Windows实现&#34; (spawn)在所有平台上,没有机械方法可以避免可能的跨平台意外。

但在实践中,我很少被这个打扰。 知道,例如,多处理可能在很大程度上取决于酸洗,我完全不知道在哪里附近玩腌菜。你遇到问题的唯一原因&#34;通过A()实例是你正在玩泡菜技巧(通过覆盖默认的__getstate__())。