消息队列与生产者消费者模型
消息队列
进程间通信
我们知道进程之间数据是相互隔离的,要想实现进程间的通信(IPC机制),就必须借助于一些技术才可以,比如multiprocessing模块中的:队列和管道,这两种方式都是可以实现进程间数据传输的,由于队列是管道+锁的方式实现,所以我们着重研究队列即可
队列
队列支持多个人从队列的一端放入数据,同样支持多个人从队列的另一端取数据(先进先出)
基本用法
Queue([maxsize]) # 创建共享的进程队列 队列底层使用管道和锁定实现。
# 参数 :maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。
代码实现
from multiprocessing import Queue
q = Queue(5) # 规定数值个数
# 存放数据
q.put(111)
q.put(222)
q.put(333)
q.put(444)
q.put(555)
q.put(555) # 第六个放不进去,但是程序会卡在这,会等待其他人取出一个后再执行
print(q.full()) # 判断是否存满 返回True或False
# 取出数据
print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get()) # 同理,如果队列内空了,也会等待有值的时候取
print(q.get_nowait()) # 如果没值直接报错
基于队列实现进程间通信(IPC机制)
from multiprocessing import Queue
def producer(q):
q.put('子进程p放的数据')
def consumer(q):
print(q.get('子进程c取的数据'))
if __name__ == '__main__':
q = Queue()
p = Process(target=producer, args=(q,))
c = Process(target=consumer, args=(q,))
p.start()
c.start()
生产者消费者模型
在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。
什么是生产者消费者模式
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据(做包子的)之后不用等待消费者(吃包子的)处理,直接扔给阻塞队列(盘子),消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
321原则
- 三种角色:生产者、消费者、仓库
- 两种关系:生产者与生产者之间是互斥关系,消费者与消费者之间是互斥关系,生产者与消费者之间是同步与互斥关系。
- 一个交易场所:仓库(这里我们用阻塞队列来表示)
代码实现(JoinableQueue模块)
from multiprocessing import JoinableQueue
import time
def producer(q, name, food):
for i in range(10):
q.put(food)
print(f'{name}生产了{food}')
time.sleep(0.1)
def consumer(q, name):
while True:
data = q.get()
print(f'{name}把{data}吃了.')
q.task_done()
if __name__ == '__main__':
q = JoinableQueue()
p1 = Process(target=producer, args=(q, '大厨jason', '葱油饼'))
p2 = Process(target=producer, args=(q, '印度阿三', '狗屎咖喱'))
p3 = Process(target=producer, args=(q, '蒙古汉子', '马奶酒'))
c = Process(target=consumer, args=(q, '大胃王老八'))
p1.start()
p2.start()
p3.start()
'''这里必须给消费者加守护进程模式,因为不加的话运行到打印'主进程'的时候因为子进程消费者还在等着处理
所以程序就会停在这.加上守护进程模式就可以实现运行完主进程代码就可以结束主进程及其子进程.所以加守护进
程模式的时候要确保生产者生产完毕以及消费者处理完毕,所以在下面要加q.join来阻塞住.'''
c.daemon = True
c.start()
p1.join()
p2.join()
p3.join()
'''调用此方法进行阻塞,直到队列中所有的项目均被消费者处理完毕方才继续向下执行(主要用在生产者生产完后使用),
搭配q.task_done()使用,q.task_done()是当队列里没有项目的时候会发出信号给join,然后join解除阻塞.
q.task_done()常用在消费者里来检测队列里的项目进度.'''
q.join()
print('主进程')