什么是生产者与消费者模式
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。
生产者—>缓冲区—>消费者
生产者与消费者模式的优点
- 解耦:
假设生产者和消费者分别是两个线程。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。如果未来消费者的代码发生变化,可能会影响到生产者的代码。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。如果没有缓冲区,那么程序的耦合度会很高,也就是说一方在很大程度上依赖另一方,一旦另一方放生改变,一方就必须做出改变。
举个例子,我们去邮局投递信件,如果不使用邮箱(也就是缓冲区),你必须得把信直接交给邮递员。有同学会说,直接给邮递员不是挺简单的嘛?其实不简单,你必须 得认识谁是邮递员,才能把信给他。这就产生了你和邮递员之间的依赖(相当于生产者和消费者的强耦合)。万一哪天邮递员 换人了,你还要重新认识一下(相当于消费者变化导致修改生产者代码)。而邮箱相对来说比较固定,你依赖它的成本就比较低(相当于和缓冲区之间的弱耦合)。 - 并发
由于生产者与消费者是两个独立的并发体,他们之间是用缓冲区通信的,生产者只需要往缓冲区里丢数据,就可以继续生产下一个数据,而消费者只需要从缓冲区拿数据即可,这样就不会因为彼此的处理速度而发生阻塞。
继续上面的例子,如果我们不使用邮箱,就得在邮局等邮递员,直到他回来,把信件交给他,这期间我们啥事儿都不能干(也就是生产者阻塞)。或者邮递员得挨家挨户问,谁要寄信(相当于消费者轮询)。
上代码解释
from queue import Queue
from threading import Thread
import time
q = Queue(maxsize=10)#声明队列最大容量为数量10
def cooker(name):
count=1
while True:
q.put('包子%d'%count)
print('%s----生产了---包子%d'%(name,count))
count+=1
time.sleep(2)
#消费者
def consumer(name):
while True:
print('%s吃了%s'%(name,q.get()))
time.sleep(1)
if __name__ == '__main__':
#厨师1
c1 = Thread(target=cooker,args=("哈哈大厨",))
c1.start()
#厨师2
c2 = Thread(target=cooker,args=("呵呵大厨",))
c2.start()
#消费者
guke1 = Thread(target=consumer,args=('小明',))
guke1.start()
guke2 = Thread(target=consumer,args=("小烈",))
guke2.start()
队列
队列分为三种:FIFO、LIFO、Priority
- FIFO即First in First Out,先进先出,Queue.Queue(maxsize=0),Queue提供了一个基本的FIFO容器,使用方法很简单,maxsize是个整数,指明了队列中能存放的数据个数的上限。一旦达到上限,插入会导致阻塞,直到队列中的数据被消费掉。如果maxsize小于或者等于0,队列大小没有限制。
from queue import Queue#导入模块
q = Queue(3)#声明队列的长度为3
q.put('1')
q.put('2')
q.put('3')
print(q.full())#判断队列是否满了
print(q.qsize())#获取当前队列消息的个数
# print(q.get())
# print(q.get())
# print(q.get())
i = 0
while i <q.qsize():
print(q.get())
print(q.empty())#判断队列是否为空
print(q.qsize())#再次返回队列里消息的个数
- LIFO即Last in First Out,后进先出,Queue.LifoQueue(maxsize=0)。与栈的类似,使用也很简单,maxsize用法同上。
from queue import LifoQueue
q=LifoQueue(3)
q.put((1,2))
q.put((2,3))
q.put((3,4))
i=0
while i<q.qsize():
print(q.get())
- PriorityQueue(maxsize=0)构造一个优先队列。maxsize用法同上。
from queue import PriorityQueue
q= PriorityQueue()
#任务不要直接put,需要封装在元组里
# 格式:(数字,消息)
#说明数字越小优先级越高
q.put((1,'文件1'))
q.put((2,'文件2'))
q.put((3,'文件3'))
q.put((-19,'文件4'))
q.put((199,'文件5'))
q.put((-9,'文件6'))
print(q.get())#(-19,'文件4')你会发现在put的同时就在队列里进行了排序
i = 0
while i < q.qsize():
print(q.get())
- 基本方法:
Queue.Queue(maxsize=0) FIFO, 如果maxsize小于1就表示队列长度无限
Queue.LifoQueue(maxsize=0) LIFO, 如果maxsize小于1就表示队列长度无限
Queue.PriorityQueue(maxsize=0) Priority, 如果maxsize小于1就表示队列长度无限
Queue.qsize() 返回队列的大小
Queue.empty() 如果队列为空,返回True,反之False
Queue.full() 如果队列满了,返回True,反之False
Queue.get([block[, timeout]]) 读队列,timeout等待时间
Queue.put(item, [block[, timeout]]) 写队列,timeout等待时间
Queue.queue.clear() 清空队列