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]