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'
添加到上面的代码中。)
答案 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。