三个关键词:消费者/生产者/模型
模型:可以理解为用于解决一类问题的统一方法/模板
生产者:比喻的是在程序中负责产生数据的任务
消费者:比喻的是在程序中负责处理数据的任务
实现
生产者 ------> queue < ------ 消费者 (通过队列进行交互,实现解耦和)
好处
实现了生产者与消费者的解耦和,生产者可以不断的生产,消费者可以不断的消费,平衡了生产者的生产能力与消费者的消费能力,从而提升了程序的整体运行效率
什么时候使用该模型
当程序中明显的出现了两类任务,一类负责产生数据,一类负责处理数据,就可以使用生产者与消费者模型来提升程序的整体效率
生产者与消费者模型的使用
import os import time import random from multiprocessing import Process, Queue def produce(q): for i in range(1, 5): res = '包子%s' % i time.sleep(random.uniform(1, 3)) q.put(res) print('厨师:%s生产了%s' % (os.getpid(), res)) def customer(q): while True: res = q.get() time.sleep(random.uniform(1, 3)) print('客户:%s吃了包子%s' % (os.getpid(), res)) if __name__ == '__main__': q = Queue() p1 = Process(target=produce, args=(q,)) c1 = Process(target=customer, args=(q,)) p1.start() c1.start() print('主进程 is done')
执行上诉代码,发现一个问题,当队列内的数据取空后(生产者生产完毕),消费者的get操作发生了阻塞,所以要寻求一种方法让消费者知道生产者生产完毕
import time import random from multiprocessing import Process,Queue def produce(name,food,q): for i in range(1,4): res = '%s%s'%(food,i) time.sleep(random.uniform(1,3)) q.put(res) print('\033[45m厨师%s生产了%s%s\033[0m'%(name,food,i)) def customer(name,q): while True: res = q.get() if res is None: break time.sleep(random.uniform(1,3)) print('\033[46m%s 吃了 %s\033[0m'%(name,res)) if __name__ == '__main__': q = Queue() p1 = Process(target=produce,args=('bob','包子',q)) p2 = Process(target=produce,args=('tom','馒头',q)) p3 = Process(target=produce,args=('tony','花卷',q)) c1 = Process(target=customer,args=('顾客1',q)) c2 = Process(target=customer,args=('顾客1',q)) p1.start() p2.start() p3.start() c1.start() c2.start() p1.join() p2.join() p3.join() q.put(None) q.put(None) print('主进程 is done')
3个join之后意味着生产者生产完毕,由主进程为队列添加结束信号(也可以在生产者内添加),消费者拿到结束信号后结束
但是这种方法需要有几个消费者就发送几个信号(消费者个数无法预知,这种做法也low)
另一种队列:JoinableQueue([maxsize]) # maxsize为允许队列存放的最大数,默认无限制
方法
1.拥有与Queue对象相同的方法
2.task_done().消费者调用该方法,记录get()方法的返回项已经被处理
3.join().调用此方法发生阻塞,直到队列中的内容全部被取干净
import time import random from multiprocessing import Process,JoinableQueue def produce(name,food,q): for i in range(1,4): res = '%s%s'%(food,i) time.sleep(random.uniform(1,3)) q.put(res) print('\033[45m厨师%s生产了%s%s\033[0m'%(name,food,i)) def customer(name,q): while True: res = q.get() time.sleep(random.uniform(1,3)) print('\033[46m%s 吃了 %s\033[0m'%(name,res)) q.task_done() if __name__ == '__main__': q = JoinableQueue() p1 = Process(target=produce,args=('bob','包子',q)) p2 = Process(target=produce,args=('tom','馒头',q)) p3 = Process(target=produce,args=('tony','花卷',q)) c1 = Process(target=customer,args=('顾客1',q)) c2 = Process(target=customer,args=('顾客1',q)) c1.daemon = True c2.daemon = True p1.start() p2.start() p3.start() c1.start() c2.start() p1.join() p2.join() p3.join() ''' 让父进程等待生产者进程执行完毕后再执行 q.join执行结束意味着--->生产者代码执行完毕 ''' q.join() ''' 等待队列被取干净 执行结束意味着父进程代码执行结束,生产者执行结束并且队列被取干净--->消费者没有存在的意义 即,这种情况下,消费者代码应该伴随着父进程代码的结束而结束(守护进程) '''