1、队列的介绍

进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的

创建队列的类(底层就是以管道和锁定的方式实现):

Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。

参数介绍:

maxsize是队列中允许最大项数,省略则无大小限制。
但需要明确:
1、队列内存放的是消息而非大数据
2、队列占用的是内存空间,因而maxsize即便是无大小限制也受限于内存大小

主要方法:

q.put方法用以插入数据到队列中。
q.get方法可以从队列读取并且删除一个元素。
from multiprocessing import Process,Queue

q=Queue(3)

#put ,get ,put_nowait,get_nowait,full,empty
q.put(1)
q.put(2)
q.put(3)
print(q.full()) #满了
# q.put(4) #再放就阻塞住了 print(q.get())
print(q.get())
print(q.get())
print(q.empty()) #空了
# print(q.get()) #再取就阻塞住了 True
1
2
3
True

二、生产者消费者模型

1、生产者消费者模型介绍

为什么要使用生产者消费者模型

生产者指的是生产数据的任务,消费者指的是处理数据的任务,在并发编程中,

如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,

才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。

为了解决这个问题于是引入了生产者和消费者模式。

什么是生产者和消费者模式

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

这个阻塞队列就是用来给生产者和消费者解耦的

2、生产者消费者模型实现

2.1 引入模型(生产一个消费一个)

import time
def producer():
for i in range(3):
res = f"包子 {i}"
time.sleep(0.5)
print(f"生产者生产了{res}")
consumer(res)
def consumer(res):
time.sleep(1)
print(f"消费者吃了{res}")
if __name__ == '__main__':
producer() 生产者生产了包子 0
消费者吃了包子 0
生产者生产了包子 1
消费者吃了包子 1
生产者生产了包子 2
消费者吃了包子 2

2.2 实现生产者消费者模型,但有小问题主进程永远不会结束

消费者不知道生产者已经完毕,一直处于等待状态,死循环

from multiprocessing import Process,Queue
import time
def producer(q):
for i in range(3):
res = f"包子 {i}"
time.sleep(0.5)
print(f"生产者生产了{res}")
# 把生产的给队列保存
q.put(res) def consumer(q):
while True:# 消费者一直接收
res = q.get()
time.sleep(1)
print(f"消费者吃了{res}")
if __name__ == '__main__':
q = Queue()
p1 = Process(target=producer,args=(q,))
p2 = Process(target=consumer,args=(q,))
p1.start()
p2.start()
print('主') 主
生产者生产了包子 0
生产者生产了包子 1
生产者生产了包子 2
消费者吃了包子 0
消费者吃了包子 1
消费者吃了包子 2

此时的问题是主进程永远不会结束,原因是:生产者p在生产完后就结束了,但是消费者c在取空了q之后,则一直处于死循环中且卡在q.get()这一步。

解决方式无非是让生产者在生产完毕后,往队列中再发一个结束信号,这样消费者在接收到结束信号后就可以break出死循环

2.3、解决办法--低阶--生产者通知消费者生产结束

队列先进先出

from multiprocessing import Process,Queue
import time
def producer(q):
for i in range(3):
res = f"包子 {i}"
time.sleep(0.5)
print(f"生产者生产了{res}")
# 把生产的给队列保存
q.put(res) def consumer(q):
while True:# 消费者一直接收
res = q.get()
if res == None:
break
time.sleep(1)
print(f"消费者吃了{res}")
if __name__ == '__main__':
q = Queue()
p1 = Process(target=producer,args=(q,))
p2 = Process(target=consumer,args=(q,))
p1.start()
p2.start()
p1.join()# 主进程等待p1子进程执行完毕--即生产者生产完毕
q.put(None)
print('主') 生产者生产了包子 0
生产者生产了包子 1
生产者生产了包子 2
消费者吃了包子 0

消费者吃了包子 1
消费者吃了包子 2

但上述解决方式,在有多个生产者和多个消费者时,我们则需要用一个很low的方式去解决,有几个消费者就需要发送几次结束信号:相当low,例如

if __name__ == '__main__':
q=Queue()
#生产者们:即厨师们
p1=Process(target=producer,args=(q,'egon1','包子'))
p2=Process(target=producer,args=(q,'egon2','骨头'))
p3=Process(target=producer,args=(q,'egon3','泔水')) #消费者们:即吃货们
c1=Process(target=consumer,args=(q,'alex1'))
c2=Process(target=consumer,args=(q,'alex2')) #开始
p1.start()
p2.start()
p3.start()
c1.start()
c2.start() p1.join()
p2.join()
p3.join()
q.put(None)
q.put(None)
q.put(None)
print('主')

2.4 JoinableQueue([maxsize]) 解决办法--高阶--消费者通知生生产者 项目已经被成功处理

这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。

JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常 q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止
from multiprocessing import Process,JoinableQueue
import time
def producer(q):
for i in range(2):
res = f"包子 {i}"
time.sleep(0.5)
print(f"生产者生产了{res}")
# 把生产的给队列保存
q.put(res)
q.join()#等待消费者把自己放入队列中的所有的数据都取走之后,消费者才结束 def consumer(q):
while True:# 消费者一直接收
res = q.get()
# if res == None:
# break
time.sleep(1)
print(f"消费者吃了{res}")
q.task_done() #发送信号给q.join() 说明已经从队列中取走一个数据并处理完毕了
if __name__ == '__main__':
q = JoinableQueue()
p1 = Process(target=producer,args=(q,))
p2 = Process(target=producer,args=(q,))
p3 = Process(target=producer,args=(q,)) #------消费者--------
c1 = Process(target=consumer,args=(q,))
c2 = Process(target=consumer,args=(q,))
# 守护进程,消费者设置成守护进程,主进程结束完后 消费者 结束
c1.daemon = True
c2.daemon = True p1.start()
p2.start()
p3.start() c1.start()
c2.start() p1.join()
p2.join()
p3.join() print('主')

3、总结

1、程序中有两类角色

一类负责生产数据(生产者)
一类负责处理数据(消费者)

2、引入生产者消费者模型为了解决的问题是

平衡生产者与消费者之间的速度差
程序解开耦合

3、如何实现生产者消费者模型

生产者<--->队列<--->消费者


5 并发编程-(进程)-队列&生产者消费者模型的更多相关文章

  1. 【Java并发编程】:生产者—消费者模型

    生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 这里实现如下情况的生产--消费模型: 生产者不断交替地生产两组数据“姓 ...

  2. #queue队列 #生产者消费者模型

    #queue队列 #生产者消费者模型 #queue队列 #有顺序的容器 #程序解耦 #提高运行效率 #class queue.Queue(maxsize=0) #先入先出 #class queue.L ...

  3. python网络编程--进程(方法和通信),锁, 队列,生产者消费者模型

    1.进程 正在进行的一个过程或者说一个任务.负责执行任务的是cpu 进程(Process: 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在 ...

  4. python 全栈开发,Day39(进程同步控制(锁,信号量,事件),进程间通信(队列,生产者消费者模型))

    昨日内容回顾 python中启动子进程并发编程并发 :多段程序看起来是同时运行的ftp 网盘不支持并发socketserver 多进程 并发异步 两个进程 分别做不同的事情 创建新进程join :阻塞 ...

  5. python 进程锁 生产者消费者模型 队列 (进程其他方法,守护进程,数据共享,进程隔离验证)

    #######################总结######### 主要理解 锁      生产者消费者模型 解耦用的   队列 共享资源的时候 是不安全的 所以用到后面的锁 守护进程:p.daem ...

  6. Learning-Python【34】:进程之生产者消费者模型

    一.什么是生产者消费者模型 生产者指的是生产数据的任务,消费者指的是处理数据的任务,在并发编程中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据.同样 ...

  7. Day034--Python--锁, 信号量, 事件, 队列, 生产者消费者模型, joinableQueue

    进程同步: 1. 锁 (重点)    锁通常被用来实现对共享资源的同步访问.为每一个共享资源创建一个Lock对象,当你需要访问该资源时,调用acquire方法来获取锁对象(如果其它线程已经获得了该锁, ...

  8. python2.0_s12_day9之day8遗留知识(queue队列&生产者消费者模型)

    4.线程 1.语法 2.join 3.线程锁之Lock\Rlock\信号量 4.将线程变为守护进程 5.Event事件 * 6.queue队列 * 7.生产者消费者模型 4.6 queue队列 que ...

  9. 队列&生产者消费者模型

    队列 ipc机制:进程通讯 管道:pipe 基于共享的内存空间 队列:pipe+锁 queue from multiprocessing import Process,Queue ### 案例一 q ...

随机推荐

  1. dgraph 基本查询语法 三

    这部分主要是查询块.查询变量.聚合操作 多名称查询 实际上就是类似多个查询数据的拼接 格式: { caro(func: allofterms(name@en, "Marc Caro" ...

  2. js 命名空间

        yui的命名空间和继承机制 var YAHOO = window.YAHOO || {};YAHOO.namespace = function(ns) {    if (!ns || !ns. ...

  3. 使用 Visual Studio Code (VSCODE)写 C51 (持续更新 2018-04-09)

    Keil C51 那代码编辑器就是上一个时代的产物, 不适合现代人使用. 但是用 Visual Studio Code (VSCODE)就舒服多了.但需要安装和配置一些扩展: 按 Ctrl + Shi ...

  4. [Python] 中文路径和中文文本文件乱码问题

    情景: Python首先读取名为log.txt的文本文件, 其中包含有文件名相对路径信息filename. 随后Python调用shutil.copy2(src, dst)对该filename文件进行 ...

  5. 【转】每天一个linux命令(41):ps命令

    原文网址:http://www.cnblogs.com/peida/archive/2012/12/19/2824418.html Linux中的ps命令是Process Status的缩写.ps命令 ...

  6. JS 的预编译和执行顺序

    脚本执行js引擎做的工作: 语法分析 预编译 解释执行

  7. Spring Cloud 入门 之 Hystrix 篇(四)

    原文地址:Spring Cloud 入门 之 Hystrix 篇(四) 博客地址:http://www.extlight.com 一.前言 在微服务应用中,服务存在一定的依赖关系,如果某个目标服务调用 ...

  8. 添加mysamba

    一. 复制/home/tingpan/openwrt/barrier_breaker/feeds/luci/applications文件夹下的luci-samba文件,将文件中的内容samba改为my ...

  9. vue 之radio绑定v-model

    示例: 单选radio <label ><input type="radio" value="0" v-model="branch& ...

  10. ApacheKylin笔记

    基本没有什么难度,只要照着官网上配置就行,这里有以下几点需要注意: HBase一定要用2.0以下的,切记.否则会报找不到方法的错误! 需要配置修改kylin.properties文件里的spark配置 ...