• 进程间通信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('33[45m%s 吃 %s33[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('33[44m%s 生产了 %s33[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也没有存在的价值了,应该随着主进程的结束而结束,所以设置成守护进程
    
    
    
    
    
    
    
    

     

  • 相关阅读:
    CF932E Team Work(第二类斯特林数)
    BZOJ 3732: Network(Kruskal重构树)
    BZOJ 2753: [SCOI2012]滑雪与时间胶囊(最小生成树)
    BZOJ 2286: [Sdoi2011]消耗战(虚树+树形dp)
    hdu 4336 Card Collector(状压dp/Min-Max反演)
    BZOJ 3622: 已经没有什么好害怕的了(二项式反演)
    BZOJ 2839: 集合计数(二项式反演)
    CF gym 101933 K. King's Colors(二项式反演)
    BZOJ 1101: [POI2007]Zap(莫比乌斯反演)
    BZOJ 3747: [POI2015]Kinoman(线段树)
  • 原文地址:https://www.cnblogs.com/layerluo/p/9600695.html
Copyright © 2020-2023  润新知