Python并发编程之数据共享与同步

一、数据共享与同步

通常,进程之间是彼此完全孤立的,唯一的通信方式是队列或者管道。但可以使用两个对象来表示共享数据。其实,这些对象使用共享内存(通过mmap模块)使访问多个进程成为可能。

Value(typecode, arg1, ... argN, lock)   

在共享内存中创建ctypes对象。typecode要么是包含array模块使用的相同类型代码的字符串,要么是来吃ctypes模块的类型对象(如ctypes.c_int, ctypes.c_double等)。所有额外的位置参数arg1 … argN将传递给指定类型的构造函数。lock是只能使用关键字调用的参数,如果把它置为true(默认值),将创建一个新的锁定来包含对值的访问。如果传入一个现有锁定,比如Lock或RLock实例,该锁定将用于同步。如果v是Value创建的共享值的实例,便可使用v.value访问底层的值。例如,读取v.value将获取值,而赋值v.value将修改值

RawValue(typecode, arg1, ..., argN)   

同Value对象,但不存在锁定。

Array(typecode, initializer, lock)   

在共享内存中创建ctypes数组。typecode描述了数组的内容, 意义与Value()函数中的相同。initializer要么是设置数组初始大小的整数,要么是项目序列,其值和大小用于初始化数组。lock是只能使用关键字调用的参数,意义与Value()函数中相同。如果a是Array创建的共享数组实例,便可使用标准的python索引、切片和迭代操作访问它的内容,其中每种操作均由锁定进行同步。对于字节字符串,a还有a.value属性,可以把整个数组当做一个字符串进行访问。

RawArray(typecode, initializer)   

同Array对象,但不存在锁定。当所编写的程序必须一次性操作大量的数组项时,如果同时使用这种数据类型和用于同步的单独锁定,性能将得到极大的提升。

除了使用Value()和Array()创建的共享值之外,multiprocessing模块还提供以下同步原语的共享版本。


原语描述
Lock互斥锁
RLock可重入的互斥锁(同一进程可以多次获得它,同时不会造成拥塞)
Semaphore信号量
Event事件
Condition条件变量

这些对象的行为与threading模块中定义的名称相同的原语相似。

需要注意的是,使用多进程后,通常不必再担心与锁定、信号量或类似构造的底层同步。在某种程度上,管道上的send()和receive()操作,以及队列上的put()和get()操作已经提供了同步功能。但是,在某些特定的设置下还是需要用到共享值和锁定。

二、使用共享数组代替管道的代码示例

下面这个例子说明了如何使用共享数组代替管道,将一个浮点数的python列表发送给另一个进程。

import multiprocessing

class FloatChannel(object):
    def __init__(self, maxsize) -> None:
        self.buffer = multiprocessing.RawArray('d', maxsize)
        self.buffer_len = multiprocessing.Value('i')
        self.empty = multiprocessing.Semaphore(1)
        self.full = multiprocessing.Semaphore(0)
        
    def send(self, values):
        # 只在缓存为空时继续
        self.empty.acquire()
        # 设置缓冲区大小
        num_items = len(values)
        self.buffer_len = num_items
        # 将值复制到缓冲区中
        self.buffer[:num_items] = values
        # 发信号通知缓冲区已满
        self.full.release()
        
    def recv(self):
        # 只在缓冲区已满时继续
        self.full.acquire()
        # 复制值
        values = self.buffer[:self.buffer_len.value]
        # 发出信号通知缓冲区为空
        self.empty.release()
        return values
    
# 性能测试,接收多条消息
def consume_test(count, ch):
    for i in range(count):
        values = ch.recv()

# 性能测试,发送多条消息
def produce_test(count, values, ch):
    for i in range(count):
        ch.send(values)
        
if __name__ == '__main__':
    ch = FloatChannel(100000)
    p  = multiprocessing.Process(target=consume_test, args=(1000, ch))
    p.start()
    
    values = [float(x) for x in range(100000)]
    produce_test(1000, values, ch)
    print("done")
    p.join()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

smart_cat

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

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

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

打赏作者

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

抵扣说明:

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

余额充值