【Python併發】【Python多進程(三)】進程間數據共享

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]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章