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。
文档 (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。