zoukankan      html  css  js  c++  java
  • python全栈开发 * 进程之间的通信,进程之间数据共享 * 180726

    进程之间的通信(IPC)队列和管道
    一.队列 基于管道实现 管道 + 锁 数据安全
    (一).队列
    队列遵循先进先出原则(FIFO)
    多用于维护秩序,买票,秒杀
    队列的所有方法:
    put()(给队列里添加数据),put_nowait(),
    get()(从队列中获取数据),get_nowait(),
    相同点:有值的时候取值
    区别:get()没有值时会阻塞
    get_nowait() 没有值时会报错
    full()(返回布尔值),empty()(返回bool值),
    qsize()(队列大小)
    示例:
            from queue import Queue
            q=Queue(5)
            print(q.qsize())   #0
            q.put(1)
            q.put(2)
            q.put(3)
            q.put(4)
            # q.put_nowait()   #已知队列长度,队列未放满数据执行此方法会报错
            # 报错信息:  TypeError: put_nowait() missing 1 required positional argument: 'item'
            q.put(5)
            print(q.qsize())   #5
            print(q.full())   #True  #队列满了返回True.
            print(q.get())
            print(q.get())
            print(q.get())
            print(q.get())
            print(q.get())
            print(q.empty())   #True    队列里无值返回True
            print(q.qsize())   #1 以上五步取出队列中的数据,此时队列长度是0.
            # q.get()    #队列里无值,用此方法程序阻塞不返回任何东西
            # q.get_nowait()    #队列里无值,用此方法程序会报错,报错信息:queue.Empt
        补充知识:
    栈 :先进后出  
    应用:三级菜单  计算文件夹的总大小
    (二).进程中的队列
    进程中的队列方法:
    empty(), full()在多进程中是不可靠
    put(),put_nowait()
    get(),get_nowait()
     示例:
        from multiprocessing import Queue
        q=Queue(3)
        q.put(2)
        q.put(3)
        q.put(5)
        print(q.qsize())     #3
        # q.put_nowait()  #  未给队列传参数或报错TypeError: put_nowait() missing 1 required positional argument: 'obj'
        print(q.get())   #2
        print(q.get())   #3
        print(q.get())   #5
        print(q.qsize())    #0
        q.get()            #无值不返回
        q.get_nowait()     #无值会报错queue.Empty
    主进程放 子进程取
    from multiprocessing import Queue,Process
        def con(q):  #定义一个con函数    传一个参数 q  是创建的队列对象
            print(q.get())  #获取队列数据,如果没有数据则一直阻塞直到有数据为止
        if __name__=="__main__":   #在这一判断条件下面创建子进程
            q=Queue()          #创建一个队列对象
            p=Process(target=con,args=(q,)) #创建一个子进程子进程对象为con,并传一个参数q.
            p.start()    #申请开启子进程
            q.put(123)   #给队列中添加数据
    子进程放,另一个子进程取
    from multiprocessing import Queue,Process
        def con(q):  #定义一个con函数    传一个参数 q  是创建的队列对象
            print(q.get())  #获取队列数据,如果没有数据则一直阻塞直到有数据为止
        if __name__=="__main__":   #在这一判断条件下面创建子进程
            q=Queue()          #创建一个队列对象
            p=Process(target=con,args=(q,)) #创建一个子进程子进程对象为con,并传一个参数q.
            p.start()    #申请开启子进程
            q.put(123)   #给队列中添加数据
    生产者消费者模型
    --解决创造(生产)数据和处理(消费)数据的效率不平衡问题
    把创造数据和处理数据放在不同的进程中
    根据他们的效率来调整进程的个数
    生产数据快 消费数据慢 内存空间的浪费
    生产数据慢 消费数据快 效率低下
     import time
        import random
        from multiprocessing import Queue,Process
        def consumer(q,name):#创建一个函数消费者
            while True:     #无限循环
                food=q.get()            #1 获取队列中数据
                if food=="stop":break   #2.判断获取的数据是否是结束符,如果是则停止获取数据(消费食物)
                print("%s吃了%s"% (name,food))   #3.提示消费者吃了生产者生产的食物
                time.sleep(random.random())      #4.消费者消费食物需要一定的时间  5_8 重复一次(消费者进程进行了两次)
    
    
        def producer(q,name,food,n=10):#创建一个函数生产者
            for i in range(n): #9.生产者生产食物的数量计数器
                time.sleep(random.random())  #10.生产食物需要消耗一定的时间
                fd=food+str(i)                 #11给食物标号
                print("%s生产了%s"% (name,fd)) #12提示生产者生产的食物
                q.put(fd)      #13把食物放进队列    14-18重复一遍 ,生产者进程进行了两次
    
        if __name__=="__main__":#在此判断条件下创建一个子进程
            q=Queue()   #创建一个队列
            c=Process(target=consumer,args=(q,"alex"))#创建一个消费者子进程,,传两个参数
            c.start() #申请开启子进程
            c1=Process(target=consumer,args=(q,"alex")) #再创建一个消费者子进程,传两个参数
            c1.start()#申请开启子进程
            p=Process(target=producer,args=(q,"太白","食物"))  #创建一个生产者子进程,传三个参数
            p.start()#申请开启子进程
            p1 = Process(target=producer, args=(q, "egon", "甜点"))#再创建一个生产者子进程,传三个参数
            p1.start()#申请开启子进程
            p.join()        #第一个生产者生产结束再执行下一步
            p1.join()       #第二个生产者生产结束再执行下一步
            q.put("stop")    #全部生产者生产结束以后 再发送结束符
            q.put("stop")    #有几个消费者就发送几个结束符
        让consumer 停下来的方法
    在所有生产者结束生产之后,向队列中放入一个结束符
    有几个消费者就向队列中放入几个结束符
    在消费者消费的过程中,接收到结束符,就结束消费的进程

    生产者消费者模型 ---JoinableQueue版
     import time
        import random
        from multiprocessing import JoinableQueue,Process
        def consumer(q,name):#创建消费者函数
            while True:         #6.无限循环
                food=q.get()     #7.获取队列中的食物
                print("%s吃了%s" %(name,food))#8提示消费者吃了食物
                time.sleep(random.random())    #9.消费者消费食物需要时间
                q.task_done()                  #10.每消费完一个食物就给生产者发送一次信息   16-20 以此类推
    
    
        def producer(q,name,food,n=10):#创建生产者函数
            for i in range(10):             #1.无限循环     11-15 以此类推
                time.sleep(random.random())  #2.生产食物需要耗费时间
                fd=food+str(i)               #3.生产食物名+序号
                print("%s生产了%s"%(name,fd))#4.提示生产者生产了食物
                q.put(fd)                     #5.将生产的食物添加到队列中
            q.join()             #等消费者全部消费结束之后才结束阻塞#
    
        if __name__=="__main__":#在此条件下创建一个子进程
            q=JoinableQueue()                                  #创建一个队列(JoinableQueue)
            c=Process(target=consumer,args=(q,"alex"))        #创建一个消费者进程两个参数
            c.daemon=True   #设置守护进程
            c.start()       #申请开启消费者进程
            c1=Process(target=consumer,args=(q,"alex"))        #在创建一个消费者进程,传两个参数
            c1.daemon=True   #设置守护进程
            c1.start()        #申请开启另一个消费者进程
            p=Process(target=producer,args=(q,"太白","食物"))   #创建一个生产者进程 传三个参数
            p.start()         #申请开启一个消费者进程
            p1=Process(target=producer,args=(q,"egon",'甜点'))  #再创建一个生产者进程,传三个参数
            p1.start()        #申请开启另一个生产者进程
            p.join()          #结束第一个生产者进程后再执行后面的代码
            p1.join()         #结束第二个生产者进程后结束主程序    (守护程序直接结束)(消费者程序结束)
    总结 :
     只有multiprocessing中的队列才能帮助你实现IPC(进程之间的通信)
        永远不可能出现数据不安全的情况,多个进程不会同时取走同一个数据
        由于先进先出的特点 + 进程通信的功能 + 数据进程安全,经常用它来完成进程之间的通
    生产者消费者模型
     生产者和消费者的效率平衡的问题
        内存的控制--队列的长度限制
        让消费者自动停下来
    JoinableQueue
    在消费数据的时候   task_done
        在生产端主进程    join
        流程:
        消费者消费完毕
        生产者结束阻塞
        主进程代码结束
        守护进程结束=>消费者结束
    二.管道       数据不安全
    示例:
        from multiprocessing import Pipe
        left,right=Pipe()
        left.send("888")
        print(right.recv())
    

     管道第一版:

     from multiprocessing import Pipe,Process
        def consumer(left,right):
            left.close()   # 一个进程中,如果接收时其中一端关闭, 另一端开启在无限循环接收中会报错,
            while True:   #左右两端都开启则可以无限循环接收,不会报错
                try:
                    print(right.recv())   #接收信息
                except EOFError:
                    break
        if __name__=="__main__":
            left,right=Pipe()    #创建一个管道
            p=Process(target=consumer,args=(left,right))  #创建一个consumer子进程,传两个参数
            p.start()  #申请开启一个子进程
            right.close()   #关闭右管道口
            for i in range(10):  #计数器
                left.send("hello")  #左管道口发送信息(发送十次)
            left.close()  #所有信息发完关闭右管道口
        EOF异常的触发:
            在这一个进程中,如果不再用这个端点了,应该close.
            这一在recv的时候,如果其他端点都被关闭了,就能够知道不会再有新的消息传进来
            此时就不会在这里阻塞等待,而是抛出一个EOFError
            close并不是关闭了整个管道,而是修改了操作系统对管道端点的引用
    一个进程发另一个进程收
     from multiprocessing import Process,Pipe
        def consumer(p,name):
            produce,consume=p
            produce.close()
            while True:
                try:
                    food=consume.recv()
                    print("%s收到%s"%(name,food))
                except EOFError:
                    break
    
    
        def producer(p,sep=10):
            produce,consume=p
            consume.close()
            for i in range(sep):
                produce.send(i)
    
    
        if __name__=="__main__":
            produce,consume=Pipe()
            for i in range(5):
                c=Process(target=consumer,args=((produce,consume),"c1"))
                c.start()
            for i in range(5):
                p=Process(target=producer,args=((produce,consume),))
                p.start()
            producer((produce,consume))
            produce.close()
            consume.close()
    进程之间的数据共享
    from  multiprocessing import Manager,Process,Lock
    def work(d,lock):#定义一个work函数 传两个参数
        with lock:
            d["count"]-=1#字典的count对应的值减一
    
    
    if __name__=="__main__":
        lock=Lock()
        m=Manager()
        dic=m.dict({"count":100})
        p_l=[]
        for i in range(100):
            p=Process(target=work,args=(dic,lock))     #创建一个work子进程 传两个参数dic,lock,一共创建一百个
            p_l.append(p)     #每创建一个进程就添加进列表中
            p.start()  #每创建一个就申请开启一个
        for p in p_l:  #循环遍历列表中每一个进程
            p.join()    #直到所有进程都结束再执行后面的代码
        print(dic)      #0    最后打印字典
  • 相关阅读:
    P4890 Never·island
    P2617 Dynamic Rankings
    P3243 [HNOI2015]菜肴制作
    P4172 [WC2006]水管局长
    P4219 [BJOI2014]大融合
    P5241 序列
    P1501 [国家集训队]Tree II
    无法读取用户配置文件,系统自动建立Temp临时用户
    组件服务 控制台打不开
    打印服务器 功能地址保护错误
  • 原文地址:https://www.cnblogs.com/J-7-H-2-F-7/p/9385187.html
Copyright © 2011-2022 走看看