Python基础_多进程数据共享

一、多进程数据共享

Python中,多进程之间的数据共享是一个复杂的主题,因为每个进程都有自己的内存空间和独立的Python解释器实例。这意味着它们不能直接共享数据,就像线程那样。但是,Python提供了几种方法来间接地实现多进程之间的数据共享。

二、使用multiprocessing.Manager对象

multiprocessing模块提供了一个Manager对象,它可以让创建可以在多个进程之间共享的数据结构,如列表和字典。Manager对象背后实际上是通过进程间通信(IPC)实现的。

**使用示例:**创建可以在多个进程之间共享的字典

from multiprocessing import Process, Manager

def func(d, i):
    d[i] = i * i

if __name__ == '__main__':
    with Manager() as manager:
        d = manager.dict()
        processes = [Process(target=func, args=(d, i)) for i in range(10)]
        for p in processes:
            p.start()
        for p in processes:
            p.join()
        print(d)
# 执行结果
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

三、使用multiprocessing.Value和multiprocessing.Array

这两个类允许创建可以在多个进程之间共享的值和数组。

它们是基于ctypes模块的,这意味着可以创建不同类型的数据结构(如整数、浮点数数组等)。

**使用示例:**使用共享类ValueArray

from multiprocessing import Process, Value, Array

def func(n, a):
    n.value = 3.1415927
    for i in range(len(a)):
        a[i] **= 2

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

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

    print(num.value)
    print(arr[:])
# 执行结果
3.1415927
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

四、使用管道和队列

尽管不是真正的“共享”数据,但multiprocessing.Pipemultiprocessing.Queue提供了进程间通信的机制。

这些对象可以在进程之间传递数据,从而实现某种形式的数据“共享”。

使用示例:Queue数据共享

from multiprocessing import Process, Queue

def func(q, i):
    q.put('hello {} times'.format(i))

if __name__ == '__main__':
    q = Queue()
    plist= [Process(target=func, args=(q, i)) for i in range(3)]
    for p in plist:
        p.start()
        p.join()
    while not q.empty():
        tmpVal = q.get()
        print(tmpVal)
# 执行结果
hello 0 times
hello 1 times
hello 2 times

五、使用共享内存

在某些情况下,可能需要直接使用操作系统的共享内存机制。可以通过multiprocessing.RawValuemultiprocessing.RawArray类来实现,但它们提供了更低的抽象级别,需要谨慎使用。

multiprocessing.RawValuemultiprocessing.RawArray 用于创建可以直接在多个进程之间共享的内存区域。

ManagerValueArray 不同,RawValueRawArray 不提供任何锁机制,因此它们更快,但同时也需要程序员负责同步以避免数据竞争。

使用 RawValueRawArray 示例:

from multiprocessing import Process, RawValue, RawArray, Lock

# 使用RawValue
def process_with_raw_value(value, lock):
    with lock:
        for _ in range(10000):  # 假设有很多次写操作
            value.value += 1

# 使用RawArray
def process_with_raw_array(arr, lock):
    with lock:
        for i in range(len(arr)):
            arr[i] **= 2  # 对数组中的每个元素进行平方操作

if __name__ == '__main__':
    # 创建一个RawValue对象,初始值为0,类型为'i'(整数)
    lock = Lock()  # 创建一个锁对象用于同步
    shared_value = RawValue('i', 0)

    # 创建一个RawArray对象,包含5个整数元素
    shared_array = RawArray('i', [1, 2, 3, 4, 5])

    # 创建并启动两个进程,分别处理RawValue和RawArray
    p1 = Process(target=process_with_raw_value, args=(shared_value, lock))
    p2 = Process(target=process_with_raw_array, args=(shared_array, lock))

    p1.start()
    p2.start()

    p1.join()
    p2.join()

    # 由于RawValue和RawArray不提供同步机制,们需要使用锁来确保数据一致性
    with lock:
        print("Shared value:", shared_value.value)  # 输出共享值的最终结果
        print("Shared array:", shared_array[:])     # 输出共享数组的最终结果
# 执行结果
Shared value: 10000
Shared array: [1, 4, 9, 16, 25]

注意:尽管 RawValueRawArray 提供了更高的性能和更灵活的数据共享方式,但它们也更难正确使用,因为需要程序员自己处理所有的同步问题。在大多数情况下,如果不需要这么底层的控制,使用 ManagerValueArray 会更简单和安全。

六、注意事项

由于GIL(全局解释器锁)的存在,共享数据在并发修改时可能会导致不可预知的行为。

因此,在共享数据时,请务必确保正确地同步进程,以避免数据竞争和不一致。


may the odds be ever in your favor ~

  • 39
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长孤秋落

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值