本文首发于
知乎
本文分为如下部分
- 引言
- 初试manager
- 注意事项
- 分布式进程
引言
在多进程中,每一个进程都有自己的变量拷贝,所以主进程中的一个变量传入其他进程修改,得到的结果仍然存储于那个进程中,主进程中这个变量其实相当于没有被修改过。为了能让其他进程的修改能够同步到主进程上来,需要创建能在多个进程之间共享的变量。
举一个例子
from multiprocessing import Process
def f1(x, l):
x += 1
l.append(2)
def f2(x, l):
x -= 2
l.append(3)
if __name__ == '__main__':
x = 0
l = [1]
p1 = Process(target=f1, args=(x, l))
p2 = Process(target=f2, args=(x, l))
p1.start()
p2.start()
p1.join()
p2.join()
print(x, l)
运行结果为
0 [1]
x l
都没有被改变,因为它们是放在其他进程中修改的。
初试manager
我们在前面的文章中提到了进程之间共享数据的一些方法,如
Queue pipe value
,不过
multiprocessing
模块还提供了一种更加高级的封装,即用
Manager
来创建变量用于进程之间共享,我们直接来看下面一个例子
from multiprocessing import Process, Manager
def f1(ns, l):
ns.x += 1
l.append(2)
def f2(ns, l):
ns.x -= 2
l.append(3)
if __name__ == '__main__':
manager = Manager()
ns = manager.Namespace()
l = manager.list([1])
ns.x = 0
p1 = Process(target=f1, args=(ns, l))
p2 = Process(target=f2, args=(ns, l))
p1.start()
p2.start()
p1.join()
p2.join()
print(ns, l)
结果如下
Namespace(x=-1) [1, 2, 3]
上面代码涉及到了
manager.Namespace()
和
manager.list()
两个方法,前者可以通过
.
来创建各种变量,后者专门用来创建list,用
manager
方法创建出来的变量可以在不同进程之中修改。
manager
创造的其他类型详见
官网
注意事项
有时候使用
manager
仍会发现变量没有被其他进程改变,比如使用
manager.Namespace()
创建列表修改无效,或
manager.list()
创建多层列表时里面列表中的元素修改无效。这是因为它们是可变对象,修改时内存地址不变,于是主进程还是读取原来的地址,独到的还是原来的值。
这个回答 中的代码非常恰当,我就直接贴在这里了
import multiprocessing
import time
def f(ns, ls, di):
ns.x += 1
ns.y[0] += 1
ns_z = ns.z
ns_z[0] += 1
ns.z = ns_z
ls[0] += 1
ls[1][0] += 1
ls_2 = ls[2]
ls_2[0] += 1
ls[2] = ls_2
di[0] += 1
di[1][0] += 1
di_2 = di[2]
di_2[0