03:进程Queue --- 生产者消费者模型
1 进程间数据隔离,两个进程进行通信,借助于Queue
2 进程间通信:IPC
-借助于Queue实现进程间通信
-借助于文件
-借助于数据库
-借助于消息队列:rabbitmq,kafka....
from multiprocessing import Process,Queue if __name__ == '__main__': # maxsize表示Queue的大小是多少,能放多少东西 queue=Queue(3) ## 放数据 queue.put('zhangsan') queue.put('liss') queue.put('wwwww') queue.put('wwwww',timeout=0.1) # queue.put_nowait('sdafsd') # # res=queue.get() # print(res) # res=queue.get() # print(res) res=queue.get() # print(res) # # 卡住 # # res=queue.get() # res=queue.get_nowait() # print(res) ''' # 实例化得到一个对象,数字表示queue的大小(默认不传参,可以当成无限大,但其实有最大值) queue=Queue(3) # 放值 # block:是否阻塞 #timeout:等待的时间 queue.put() #取值 # block:是否阻塞 #timeout:等待的时间 queue.get() # 不等待,如果满了,就报错 queue.put_nowait() # 去取值,如果没有值,直接报错 res=queue.get_nowait() #查看这个queue是否满 queue.full() #查看queue是否是空的 queue.empty() # 查看queue中有几个值 queue.qsize() '''
2 通过Queue实现进程间通信
from multiprocessing import Process,Queue import os import time def task(queue): print('我这个进程%s开始放数据了'%os.getpid()) time.sleep(10) queue.put('lqz is handsome') print('%s我放完了' % os.getpid()) if __name__ == '__main__': #不写数字,表示可以任意长度 queue=Queue() p=Process(target=task,args=[queue,]) p.start() res=queue.get() #会卡在这 print(res)
3 批量生产数据放入Queue再批量取出
from multiprocessing import Process,Queue import os def get_task(queue): res=queue.get() print('%s这个进程取了数据:%s'%(os.getpid(),res)) def put_task(queue): queue.put('%s:放了数据'%os.getpid()) if __name__ == '__main__': queue=Queue(1) p1=Process(target=put_task,args=[queue]) p2=Process(target=put_task,args=[queue]) p1.start() p2.start() p3=Process(target=get_task,args=[queue]) p4=Process(target=get_task,args=[queue]) p3.start() p4.start()
4 生产者消费者模型(重点)
from multiprocessing import Process, Queue # import os # # import time # import random # def producer(queue): # # 生产的东西,放到Queue中 # for i in range(10): # data = '%s这个厨师,整了第%s个包子' % (os.getpid(), i) # print(data) # # 模拟一下延迟 # time.sleep(random.randint(1,3)) # queue.put('第%s个包子'%i) # # # def consumer(queue): # # 消费者从queue中取数据,消费(吃包子) # while True: # # res=queue.get() # # 模拟一下延迟 # time.sleep(random.randint(1, 3)) # print('%s这个消费者,吃了%s'%(os.getpid(),res)) # # # # if __name__ == '__main__': # queue=Queue(3) # p=Process(target=producer,args=[queue,]) # p.start() # # p1=Process(target=consumer,args=[queue,]) # p1.start() ###### 改良(生产者以及不生产东西了,但是消费者还在等着拿) # import os # # import time # import random # def producer(queue): # # 生产的东西,放到Queue中 # for i in range(10): # data = '%s这个厨师,整了第%s个包子' % (os.getpid(), i) # print(data) # # 模拟一下延迟 # time.sleep(random.randint(1,3)) # queue.put('第%s个包子'%i) # # 生产完了,在queue中放一个None # queue.put(None) # # # def consumer(queue): # # 消费者从queue中取数据,消费(吃包子) # while True: # # res=queue.get() # if not res:break # 如果去到空,说明打烊了(生产者不生产了),退出 # # 模拟一下延迟 # time.sleep(random.randint(1, 3)) # print('%s这个消费者,吃了%s'%(os.getpid(),res)) # # # # if __name__ == '__main__': # queue=Queue(3) # p=Process(target=producer,args=[queue,]) # p.start() # # p1=Process(target=consumer,args=[queue,]) # p1.start() #### 把put none 放在主进程中执行 import os # import time # import random # def producer(queue): # # 生产的东西,放到Queue中 # for i in range(10): # data = '%s这个厨师,整了第%s个包子' % (os.getpid(), i) # print(data) # # 模拟一下延迟 # time.sleep(random.randint(1,3)) # queue.put('第%s个包子'%i) # # # # def consumer(queue): # # 消费者从queue中取数据,消费(吃包子) # while True: # # res=queue.get() # if not res:break # 如果去到空,说明打烊了(生产者不生产了),退出 # # 模拟一下延迟 # time.sleep(random.randint(1, 3)) # print('%s这个消费者,吃了%s'%(os.getpid(),res)) # # # # if __name__ == '__main__': # queue=Queue(3) # p=Process(target=producer,args=[queue,]) # p.start() # # p1=Process(target=consumer,args=[queue,]) # p1.start() # # # 如果把put None放在这,会有问题 # # 主进程会先执行这句话,消费进程读到None,直接结束,生产者进程没有结束,于是生产一直在生产,消费已经不消费了 # # 直到Queue满了,就一直卡在这了 # # queue.put(None) # # ### 现在就要放在这,你把问题解决 # p.join() # queue.put(None)
5 多个生产者多个消费者的生产者消费者模型
# 多个生产者在生产,多个消费者在消费 # import time # import random # def producer(queue,food): # # 生产的东西,放到Queue中 # for i in range(10): # data = '%s这个厨师,做了第%s个%s' % (os.getpid(), i,food) # print(data) # # 模拟一下延迟 # time.sleep(random.randint(1,3)) # queue.put('第%s个%s'%(i,food)) # # # def consumer(queue): # # 消费者从queue中取数据,消费(吃包子) # while True: # res=queue.get() # if not res:break # 如果去到空,说明打烊了(生产者不生产了),退出 # # 模拟一下延迟 # time.sleep(random.randint(1, 3)) # print('%s这个消费者,吃了%s'%(os.getpid(),res)) # # # # if __name__ == '__main__': # queue=Queue(3) # ##起了三个生产者 # p1=Process(target=producer,args=[queue,'包子']) # p2=Process(target=producer,args=[queue,'骨头']) # p3=Process(target=producer,args=[queue,'泔水']) # p1.start() # p2.start() # p3.start() # # # # # 起了两个消费者 # c1=Process(target=consumer,args=[queue,]) # c2=Process(target=consumer,args=[queue,]) # c1.start() # c2.start() # # ##等三个生产者都生产完,放三个None # p1.join() # p2.join() # p3.join() # queue.put(None) # queue.put(None) # queue.put(None) ##如果消费者多,比生产者多出来的消费者不会停 import time import random def producer(queue, food,name): # 生产的东西,放到Queue中 for i in range(10): data = '%s:这个厨师,做了第%s个%s' % (name, i, food) print(data) # 模拟一下延迟 time.sleep(random.randint(1, 3)) queue.put('第%s个%s' % (i, food)) def consumer(queue,name): # 消费者从queue中取数据,消费(吃包子) while True: try: res = queue.get(timeout=20) # 模拟一下延迟 time.sleep(random.randint(1, 3)) print('%s这个消费者,吃了%s' % (name, res)) except Exception as e: print(e) break if __name__ == '__main__': queue = Queue(3) ##起了三个生产者 p1 = Process(target=producer, args=[queue, '包子','egon']) p2 = Process(target=producer, args=[queue, '骨头','lqz']) p3 = Process(target=producer, args=[queue, '泔水','jsason']) p1.start() p2.start() p3.start() # 起了两个消费者 c1 = Process(target=consumer, args=[queue, '孟良']) c2 = Process(target=consumer, args=[queue,'池劲涛' ]) c3 = Process(target=consumer, args=[queue,'池劲涛' ]) c4 = Process(target=consumer, args=[queue,'池劲涛' ]) c1.start() c2.start() c3.start() c4.start()
6 进程间数据共享(了解)
from multiprocessing import Process,Manager,Lock # 魔法方法:类内以__开头__结尾的方法,都叫魔法方法,某种情况下会触发它的执行 ''' __init__ :类()触发 __new__: __getattr__ __setattr__ __getitem__ __setitem__ ''' # def task(dic,lock): # # lock.acquire() # # dic['count']-=1 # # lock.release() # with lock: # dic['count'] -= 1 # # if __name__ == '__main__': # lock = Lock() # with Manager() as m: # # 如果直接定义dict,这个dict在多个进程中其实是多份,进程如果改,只改了自己的 # #如果定义的是m.dict({'count': 100}),多个进程之间就可以共享这个数据 # dic = m.dict({'count': 100}) # # p_l = [] # for i in range(100): # p = Process(target=task, args=(dic, lock)) # p_l.append(p) # p.start() # for p in p_l: # p.join() def task(dic,lock): with lock: dic['count'] -= 1 if __name__ == '__main__': lock = Lock() dic={'count':100} p_l = [] for i in range(100): p = Process(target=task, args=(dic, lock)) p_l.append(p) p.start() for p in p_l: p.join() print(dic)
7 线程概念
如果把我们上课的过程看成一个进程的话,那么我们要做的是耳朵听老师讲课,手上还要记笔记,脑子还要思考问题,这样才能高效的完成听课的任务。而如果只提供进程这个机制的话,上面这三件事将不能同时执行,同一时间只能做一件事,听的时候就不能记笔记,也不能用脑子思考,这是其一;如果老师在黑板上写演算过程,我们开始记笔记,而老师突然有一步推不下去了,阻塞住了,他在那边思考着,而我们呢,也不能干其他事,即使你想趁此时思考一下刚才没听懂的一个问题都不行,这是其二
#进程是资源分配的最小单位,线程是CPU调度的最小单位。每一个进程中至少有一个线程。 from threading import Thread from queue import Queue import os import time def task(): time.sleep(3) print('我是子线程执行的') print(os.getpid()) if __name__ == '__main__': # 启动线程 ctime = time.time() t = Thread(target=task) t.start() # task() time.sleep(3) print(os.getpid()) print(time.time() - ctime)
总结
1 Queue:进程间通信 -实例化得到一个对象 -对象.put() -对象.get() 2 生产者消费者模型 3 通过共享变量来共享数据(进程间数据是隔离的) -Manager实现多个进程操作同一个变量 -加锁 4 线程,每个进程下最少有一个线程,cup调度的最小单位 5 python如何开启线程
愿君前程似锦,归来仍是少年