进程间通信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也没有存在的价值了,应该随着主进程的结束而结束,所以设置成守护进程

 


 

 

 

posted @ 2018-09-06 20:18  大张哥  阅读(443)  评论(0编辑  收藏  举报