Python进程间数据共享主要有两种方式,一种是共享内存,另一种是通过数据管理其(Manager)来实现。
一、共享内存
共享内存允许多个进程共享一个存储区域,一个进程写入共享内存中的信息,其他进程可以方便的读取。
在Python中可以使用Value、Array将数据存储在共享内存中,也可以使用模块multiprocessing.sharedctypes自定义共享内存的ctypes对象。
1.1 不使用共享内存
from multiprocessing import Process, Lock
import time
num = 0
def add_one(lock):
global num
for i in range(3):
lock.acquire()
num += 1
print(num)
time.sleep(1)
lock.release()
if __name__ == '__main__':
lock = Lock()
p1 = Process(target=add_one, args=(lock,))
p2 = Process(target=add_one, args=(lock,))
p1.start()
p2.start()
输出:
1
1
2
2
3
3
结果分析:
由于变量num并没有共享,而是每个进程一个副本,因此1,2,3才会出现2次。
1.2 使用共享内存
from multiprocessing import Process, Lock, Value
import time
def add_one(lock, num):
for i in range(3):
lock.acquire()
num.value += 1
print(num.value)
time.sleep(1)
lock.release()
if __name__ == '__main__':
num = Value('i', 0)
lock = Lock()
p1 = Process(target=add_one, args=(lock, num))
p2 = Process(target=add_one, args=(lock, num))
p1.start()
p2.start()
输出:
1
2
3
4
5
6
1.3 使用Array进行内存共享
from multiprocessing.sharedctypes import Array
from multiprocessing import Process, Lock
def add_one(lock, arr):
lock.acquire()
for i in range(len(arr)):
arr[i] += 1
lock.release()
print(arr[:])
if __name__ == '__main__':
lock = Lock()
arr = Array('i', range(10))
print(arr[:])
p1 = Process(target=add_one, args=(lock, arr))
p2 = Process(target=add_one, args=(lock, arr))
p1.start()
p2.start()
输出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
1.4 自定义共享内存
from multiprocessing import Process, Lock
from multiprocessing.sharedctypes import Value, Array
from ctypes import Structure, c_double
# 自定义数据结构
class Point(Structure):
_fields_ = [('x', c_double), ('y', c_double)]
def modify(n, x, s, A):
n.value **= 2
x.value **= 2
s.value = s.value.upper()
for a in A:
a.x **= 2
a.y **= 2
if __name__ == '__main__':
lock = Lock()
n = Value('i', 7) # 定义int型
x = Value(c_double, 1.0/3.0, lock=False) # 定义ctypes类型
s = Array('c', b'hello world', lock=lock) # 定义字符串
A = Array(Point, [(1.875, -6.25), (-5.75, 2.0), (2.375, 9.5)], lock=lock) # 定义Point类型的数组
p = Process(target=modify, args=(n, x, s, A))
p.start()
p.join()
print(n.value)
print(x.value)
print(s.value)
print([(a.x, a.y) for a in A])
输出:
49
0.1111111111111111
b'HELLO WORLD'
[(3.515625, 39.0625), (33.0625, 4.0), (5.640625, 90.25)]
二、 Manager(数据管理器)
Manager的作用是提供多进程共享的全局变量,Manager()方法会返回一个对象,该对象控制着一个服务进程,该进程中保存的对象运行其他进程使用代理进行操作。
Manager支持的类型有:list,dict,Namespace,Lock,RLock,Semaphore,BoundedSemaphore,Condition,Event,Queue,Value和Array。
from multiprocessing import Process, Lock, Manager
def f(n, d, l, lock):
lock.acquire()
d[str(n)] = n
l[n] = -99
lock.release()
if __name__ == '__main__':
lock = Lock()
with Manager() as manager:
d = manager.dict() # 空字典
l = manager.list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 启动10个进程,不同的进程对d和l中的不同元素进行操作
for i in range(10):
p = Process(target=f, args=(i, d, l, lock))
p.start()
p.join()
print(d)
print(l)
输出:
{'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
[-99, -99, -99, -99, -99, -99, -99, -99, -99, -99]