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