进程间通信ipc机制 生产者消费者模型(进程部分)
IPC 机制有两种 一个是管道 一个是队列(队列=管道+锁)
管道用来实现两个进程连接进行通信
subprocess.Popen('tasklist',shell=True,) 就相当于 p=Process(target=tasklist) 只是发送一个信号出去 就是开一个子进程
主进程要想拿到子进程命令的运行结果,子进程的运行结果就是一堆数据,放在子进程的内存里,主进程要想拿就是子进程把运行结果丢到管道里面subprocess.Popen(‘tasklist’,shell=True,stdout=subprocess.PIPE) stdout 就是造了一个管道出来 子进程一旦运行就是把运行结果丢到管道里面 ,管道其实就是一个虚拟的共享空间,父进程想拿就直接去共享空间拿
队列 (先进先出) 需要使用到 from multiprocessing import Queue
Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。
Queue() 里面只有一个maxsize maxsize是队列中允许最大项数,省略则无大小限制
q=Queue(3)
q.put(2)
q.put({'x':2})
q.put(['22']) put 把数据放入Queue
如果设置的maxsize是2 那么程序会阻塞住 等待有人把里面的数据取走 再把最后一个存入这就相当于与管道+锁
如果maxsize不设置参数 表示Queue 可以存很多值 但不是无限的也有上限 而且Queue存放消息类信息的小数据,不应该存放文件类的大数据。
取出值就是 q.get() 因为是队列先进先出 先出来的是2 如果里面有两个值 但是有三个get 那么和上面一样阻塞
q.put 还有其他的参数 有block 默认是True block意思是锁 参数timeout 默认是-1 -1就是一直等待 意思是阻塞后等待时间 如果阻塞了过了timeout的时间那么会跑出异常
q.put_nowait 这个意思就是q.put(1,block=Flase) 直接不等待
q.get 和 q.get_nowait 和之前的一样 只是get timeout返回的是队列为空的异常
生产者消费者模型
什么是生产者消费者模型
生产者:代指生产数据的任务
消费者:代指处理数据的任务
该模型的工作方式:
生产生产数据传递消费者处理
实现方式:
生产者---->队列<------消费者
为何要用
当程序中出现明细的两类任务,一类负责生产数据,一类负责处理数据
就可以引入生产者消费者模型来实现生产者与消费者的解耦合,平衡生产能力与消费能力,从提升效率
这是最终优化版本 下面链接内有一步步优化过程
http://www.cnblogs.com/linhaifeng/articles/7428874.html
#JoinableQueue([maxsize]):这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。 #参数介绍: maxsize是队列中允许最大项数,省略则无大小限制。 #方法介绍: JoinableQueue的实例p除了与Queue对象相同的方法之外还具有: q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常 q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止 from multiprocessing import Process,JoinableQueue import time,random,os def consumer(q): while True: res=q.get() time.sleep(random.randint(1,3)) print('\033[45m%s 吃 %s\033[0m' %(os.getpid(),res)) q.task_done() #向q.join()发送一次信号,证明一个数据已经被取走了 def producer(name,q): for i in range(10): time.sleep(random.randint(1,3)) res='%s%s' %(name,i) q.put(res) print('\033[44m%s 生产了 %s\033[0m' %(os.getpid(),res)) 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 #开始 p_l=[p1,p2,p3,c1,c2] for p in p_l: p.start() p1.join() p2.join() p3.join() print('主') #主进程等--->p1,p2,p3等---->c1,c2 #p1,p2,p3结束了,证明c1,c2肯定全都收完了p1,p2,p3发到队列的数据 #因而c1,c2也没有存在的价值了,应该随着主进程的结束而结束,所以设置成守护进程