Python多进程-进程间共享数据
Python 多线程之间共享变量很简单,直接定义全局 global 变量即可。而多进程之间是相互独立的执行单元,这种方法就不可行了。
不过 Python 标准库已经给我们提供了这样的能力,使用起来也很简单。但要分两种情况来看,一种是 Process 多进程,一种是 Pool 进程池的方式。
Process 多进程
使用 Process 定义的多进程之间共享变量可以直接使用 multiprocessing 下的 Value,Array,Queue 等,如果要共享 list,dict,可以使用强大的 Manager 模块。
import multiprocessing
def func(num):
# 共享数值型变量
# num.value = 2
# 共享数组型变量
num[2] = 9999
if __name__ == '__main__':
# 共享数值型变量
# num = multiprocessing.Value('d', 1)
# print(num.value)
# 共享数组型变量
num = multiprocessing.Array('i', [1, 2, 3, 4, 5])
print(num[:])
p = multiprocessing.Process(target=func, args=(num,))
p.start()
p.join()
# 共享数值型变量
# print(num.value)
# 共享数组型变量
print(num[:])
Pool 进程池
进程池之间共享变量是不能使用上文方式的,因为进程池内进程关系并非父子进程,想要共享,必须使用 Manager 模块来定义。
from multiprocessing import Pool, Manager
def func(my_list, my_dict):
my_list.append(10)
my_list.append(11)
my_dict['a'] = 1
my_dict['b'] = 2
if __name__ == '__main__':
manager = Manager()
my_list = manager.list()
my_dict = manager.dict()
pool = Pool(processes=2)
for i in range(0, 2):
pool.apply_async(func, (my_list, my_dict))
pool.close()
pool.join()
print(my_list)
print(my_dict)
还有一点需要注意,在共享 list 时,像下面这样写 func 是不起作用的。
def func(my_list, my_dict):
my_list = [10, 11]
my_dict['a'] = 1
my_dict['b'] = 2
这样写相当于重新定义了一个局部变量,并没有作用到原来的 list 上,必须使用 append,extend 等方法。
case2
Value、Array是通过共享内存的方式共享数据
Manager是通过共享进程的方式共享数据。
Value\Array
实例代码:
import multiprocessing
#Value/Array
def func1(a,arr):
a.value=3.14
for i in range(len(arr)):
arr[i]=-arr[i]
if __name__ == '__main__':
num=multiprocessing.Value('d',1.0)#num=0
arr=multiprocessing.Array('i',range(10))#arr=range(10)
p=multiprocessing.Process(target=func1,args=(num,arr))
p.start()
p.join()
print num.value
print arr[:]
执行结果:
3.14
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
1
2
3
Manager管理的共享数据类型有:Value、Array、dict、list、Lock、Semaphore等等,同时Manager还可以共享类的实例对象。
实例代码:
from multiprocessing import Process,Manager
def func1(shareList,shareValue,shareDict,lock):
with lock:
shareValue.value+=1
shareDict[1]='1'
shareDict[2]='2'
for i in xrange(len(shareList)):
shareList[i]+=1
if __name__ == '__main__':
manager=Manager()
list1=manager.list([1,2,3,4,5])
dict1=manager.dict()
array1=manager.Array('i',range(10))
value1=manager.Value('i',1)
lock=manager.Lock()
proc=[Process(target=func1,args=(list1,value1,dict1,lock)) for i in xrange(20)]
for p in proc:
p.start()
for p in proc:
p.join()
print list1
print dict1
print array1
print value1
执行结果:
[21, 22, 23, 24, 25]
{1: '1', 2: '2'}
array('i', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
Value('i', 21)
1
2
3
4
通过Manager进程间共享实例对象:
from multiprocessing import Process,Value,Lock
from multiprocessing.managers import BaseManager
class Employee(object):
def __init__(self,name,salary):
self.name=name
self.salary=Value('i',salary)
def increase(self):
self.salary.value+=100
def getPay(self):
return self.name+':'+str(self.salary.value)
class MyManager(BaseManager):
pass
def Manager2():
m=MyManager()
m.start()
return m
MyManager.register('Employee',Employee)
def func1(em,lock):
with lock:
em.increase()
if __name__ == '__main__':
manager=Manager2()
em=manager.Employee('zhangsan',1000)
lock=Lock()
proces=[Process(target=func1,args=(em,lock))for i in xrange(10)]
for p in proces:
p.start()
for p in proces:
p.join()
print em.getPay()