生产者消费者模型:
为什么要使用生产者和消费者模式
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。
什么是生产者消费者模式
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
这就像,在餐厅,厨师做好菜,不需要直接和客户交流,而是交给前台,而客户去饭菜也不需要不找厨师,直接去前台领取即可,这也是一个结耦的过程。
大白话: 厨师在生产包子的时候,假如一分钟做20个包子,但是吃包子的用户就一个人,吃不过来(产生浪费了),反过来,厨师一分钟做一个包子,吃包子的用户有20个(包子明显就不够吃了),就相当于20个子吃包子用户在大量等待,所以为了解决这种需求,需要加一个中间介质,这个中间介质来平衡两边的事情(也就是服务员,当然用包子蒸笼更加形象些,做好的包子放到蒸笼里面,用户需要购买的时候,从蒸笼里面拿就可以了,这个时候我们只需要维护着这个蒸笼里面有多少包子就行了,而且如果蒸笼满了,我就不需要在做了).这样就平衡了(解耦)
下面示例模仿生产消费者模型:
import time,random
import queue,threading
q = queue.Queue() #这个就相当于中间介质
def Producer(name): #生产包子
count = 0
while count <10:
print("making........")
time.sleep(random.randrange(3))
q.put(count)
print('Producer %s has produced %s baozi..' %(name, count))
count +=1
print("ok......")
def Consumer(name): #消费包子
count = 0
while count <10:
time.sleep(random.randrange(4))
if not q.empty():
data = q.get()
print('\033[32;1mConsumer %s has eat %s baozi...\033[0m' %(name, data))
else:
print("-----no baozi anymore----")
count +=1
#开4个线程去处理吃包子,这时候会打印20条no baozi anymore 因为只生产了10个包子 有3个线程去吃,每个线程吃10个包子
p1 = threading.Thread(target=Producer, args=('A',)) #线程1生产包子
c1 = threading.Thread(target=Consumer, args=('B',)) #线程2吃包子
c2 = threading.Thread(target=Consumer, args=('C',)) #线程3吃包子
c3 = threading.Thread(target=Consumer, args=('D',)) #线程4吃包子
p1.start()
c1.start()
c2.start()
c3.start()
q.task_done() 和 q.join()示例
import time,random
import queue,threading
q = queue.Queue()
def Producer(name):
count = 0
while count <10:
print("making........")
time.sleep(2)
q.put(count)
print('Producer %s has produced %s baozi..' %(name, count))
count +=1
q.task_done() #这里面发送一个完成的信息给队里q (q.join() )
print("ok......")
def Consumer(name):
count = 0
while count <10:
q.join() #这里面接收到队里q有完成的信息后,就接着运行下面代码,不然会一直在这卡死状态,等待上面生成完包子的信息(同理如果这是q.task_done(),就会产生吃完包子的消息,上面q.join()接收消息后接着生产)
data = q.get()
print('\033[32;1mConsumer %s has eat %s baozi...\033[0m' %(name, data))
count +=1
p1 = threading.Thread(target=Producer, args=('A',))
c1 = threading.Thread(target=Consumer, args=('B',))
c2 = threading.Thread(target=Consumer, args=('C',))
# c3 = threading.Thread(target=Consumer, args=('D',))
p1.start()
c1.start()
c2.start()
# c3.start()