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

multiprocessing.Process (with spawn method): which objects are inherited?

文档 (python 3.4) 用 spawn、"the child process will only inherit those resources necessary to run the process object's run() method" 解释了这一点。

但哪些对象是 "necessary"?我阅读它的方式向我表明,可以从 run() 内部到达的所有对象都是 "necessary",包括作为 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' 切换到 [=20,它也会影响结果=] 在 Ubuntu 下。我现在在上面的代码中添加了 global x。)

这与 classes 在被发送到派生进程时被 pickle 的方式有关。 class 的 pickled 版本并不真正包含其内部状态,而只包含 class:

的模块和名称
class A:
   y = 0

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

这里没有关于y的信息,相当于对class的引用。

当作为参数传递给 g 时,class 将在生成的进程中被解封,如果需要,它将导入其模块(此处为 __main__)和 return对 class 的引用,因此在 main 函数中对其所做的更改不会影响它,因为 if __name__ == "__main__" 块不会在子进程中执行。 f直接在其模块中使用了class,所以效果基本一样。

x显示不同值的原因有点不同。您的 f 函数将从模块打印 global 变量 x。在你的 main() 函数中你有另一个 local 变量 x,所以在这里设置 x = 1 不会影响模块级别 x既没有进程。它作为参数传递给 g,因此在这种情况下,它的本地值将是 1。