multiprocessing.Process(使用spawn方法):继承哪些对象?

时间:2015-03-22 19:42:59

标签: python python-3.x multiprocessing python-multiprocessing

docs(python 3.4)解释了spawn,"子进程只会继承运行进程对象run()方法"所需的那些资源。

但是哪些对象是必要的"?我阅读它的方式向我建议,可以从run()内部到达的所有对象都是"必要的",包括作为args传递给Process.__init__的参数,以及存储在全局变量中的任何内容,以及在全局范围内定义的类,函数及其属性。但是,这是不正确的;以下代码确认存储在全局变量中的对象不会被继承:

# running under python 3.4 / Windows
# but behaves the same under Unix
import multiprocessing as mp

x = 0
class A:
    y = 0

def f():
    print(x) # 0
    print(A.y) # 0

def g(x, A):
    print(x) # 1
    print(A.y) # 0; really, not even args are inherited?

def main():
    global x
    x = 1
    A.y = 1
    p = mp.Process(target = f)
    p.start()
    q = mp.Process(target = g, args = (x, A))
    q.start()


if __name__=="__main__":
    mp.set_start_method('spawn')
    main()

是否有明确的规则说明哪些对象是继承的?

编辑:

确认:在Ubuntu上运行它会产生相同的输出。 (感谢@mata澄清我忘了将global x添加到main()。这个遗漏让我的例子变得混乱;如果我将'spawn'切换为{{1},它也会影响结果在Ubuntu下。我现在将'fork'添加到上面的代码中。)

1 个答案:

答案 0 :(得分:5)

这与发送到生成的进程时类被pickle的方式有关。类的pickle版本并不真正包含其内部状态,只包含模块和类的名称:

class A:
   y = 0

pickle.dumps(A)
# b'\x80\x03c__main__\nA\nq\x00.'

此处没有关于y的信息,它与该类的引用相当。

当作为argumeht传递给g时,将在生成的进程中对类进行unpickled,如果需要,将导入其模块(此处为__main__)并返回对类的引用,因此对它在main函数中不会影响它,因为if __name__ == "__main__"块不会在子流程中执行。 f直接在其模块中使用该类,因此效果基本相同。

x显示不同值的原因略有不同。您的f函数将从模块中打印全局变量x。在main()函数中,您有另一个本地变量x,因此在此处设置x = 1不会影响模块级x流程。它作为参数传递给g,因此在这种情况下,它将使本地值为1。