沐风2021-进程间数据的共享

[复制链接]
作者: ecithy | 时间: 2021-5-30 19:56:40 | python基础|
0 108
发表于 2021-5-30 19:56:40| 显示全部楼层 |阅读模式

进程是资源分配的最小单元,每个进程中都维护自己独立的数据,不共享。

import multiprocessing


def task(data):
    data.append(666)


if __name__ == '__main__':
    data_list = []
    p = multiprocessing.Process(target=task, args=(data_list,))
    p.start()
    p.join()

    print("主进程:", data_list) # []

共享内存

可以使用 ValueArray 将数据存储在共享内存映射中。例如,以下代码:

from multiprocessing import Process, Value, Array

def f(n, a):
    n.value = 3.1415927
    for i in range(len(a)):
        a[i] = -a[i]

if __name__ == '__main__':
    num = Value('d', 0.0)
    arr = Array('i', range(10))

    p = Process(target=f, args=(num, arr))
    p.start()
    p.join()

    print(num.value)
    print(arr[:])
3.1415927
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

创建 num 和 arr 时使用的 'd' 和 'i' 参数是 array 模块使用的类型的 typecode : 'd' 表示双精度浮点数, 'i' 表示有符号整数。这些共享对象将是进程和线程安全的。

为了更灵活地使用共享内存,可以使用 multiprocessing.sharedctypes 模块,该模块支持创建从共享内存分配的任意ctypes对象。

服务进程

from multiprocessing import Process, Manager

def f(d, l):
    d[1] = '1'
    d['2'] = 2
    d[0.25] = None
    l.reverse()

if __name__ == '__main__':
    with Manager() as manager:
        d = manager.dict()
        l = manager.list(range(10))

        p = Process(target=f, args=(d, l))
        p.start()
        p.join()

        print(d)
        print(l)
{1: '1', '2': 2, 0.25: None}
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

使用服务进程的管理器比使用共享内存对象更灵活,因为它们可以支持任意对象类型。此外,单个管理器可以通过网络由不同计算机上的进程共享。但是,它们比使用共享内存慢。

交换对象

multiprocessing 支持进程之间的两种通信通道:

队列

from multiprocessing import Process, Queue

def f(q):
q.put(['沐风', 666, '精易'])

if __name__ == '__main__':
q = Queue()
p = Process(target=f, args=(q, ))
p.start()
p.join()
print(q.get())  # "['沐风', 666, '精易']"

队列是线程和进程安全的。

管道

Pipe() 函数返回一个由管道连接的连接对象,默认情况下是双工(双向)。例如:

from multiprocessing import Process, Pipe


def f(conn):
    conn.send(['沐风', 666, '精易'])
    conn.close()


if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    p = Process(target=f, args=(child_conn, ))
    p.start()
    p.join()

    data = parent_conn.recv()
    print(data)  # ['沐风', 666, '精易']
    print("主进程接收:", data)  # 主进程接收: ['沐风', 666, '精易']
    parent_conn.send(666)

返回的两个连接对象 Pipe() 表示管道的两端。每个连接对象都有 send() 和 recv() 方法(相互之间的)。请注意,如果两个进程(或线程)同时尝试读取或写入管道的 同一 端,则管道中的数据可能会损坏。当然,在不同进程中同时使用管道的不同端的情况下不存在损坏的风险。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

!jz_fbzt! 快速回复 !jz_sctz! !jz_fhlb! 按钮
快速回复 返回列表 返回顶部