• 37、进程之间的通信


    1、生产者消费者模型Queue:队列(管道+锁,双向通信)

        为了解决数据供需不平衡的情况(即生产者生产的多或者消费者消费的多造成的失衡),有一种解决的方法:子进程生产数据,子进程处理数据。

    生产者消费者模型:

      1、消费者要处理多少数据是不确定的

      2、所以只能用while循环来处理数据,但是while循环无法结束

      3、需要生产者发送信号

      4、有多少个消费者,就需要发送多少个信号

      5、但是发送的信号数量需要根据生产者和消费者的数量进行计算,所以非常不方便。   

    import time
    import random
    from multiprocessing import Process
    from multiprocessing import Queue
    
    def producer(q,food):
        for i in range(5):
            q.put('%s-%s'%(food,i))
            print('生产了%s'%(food))
            time.sleep(random.random())
        q.put(None)
        q.put(None)
        q.put(None)
    
    def consumer(q,name):
        while True:
            food=q.get()
            if food == None:break
            print('%s吃了%s'%(name,food))
    
    
    if __name__ =='__main__':
        q=Queue()
        p1=Process(target=producer,args=(q,'骨头'))
        p1.start()
        p2=Process(target=producer,args=(q,'泔水'))
        p2.start()
        p3 = Process(target=consumer, args=(q, 'alex'))
        p3.start()
        p4 = Process(target=consumer, args=(q, 'egon'))
        p4.start()
        p5 = Process(target=consumer, args=(q, 'jin'))
        p5.start()
        

    2、joinableQueue:顺序为:生产者生产的数据全部被消费------->生产者进程结束------->主进程执行代码结束—-->消费者守护进程结束。

      put和get的一个计数机制,每次get数据之后发送task_done,put端接收到计数-1,直到计数为0就能感知到。

    import time
    import random
    from multiprocessing import Process
    from multiprocessing import JoinableQueue
    # put   q.join
    # get  处理数据 task_done 消费完了
    def producer(q,food):
        for i in range(5):
            q.put('%s-%s'%(food,i))
            print('生产了%s'%food)
            # time.sleep(random.randint(1,3))
            time.sleep(random.random())
        q.join()  # 等待 消费者 把所有的数据都处理完
    
    def consumer(q,name):
        while True:
            food = q.get()   # 生产者不生产还是生产的慢
            print('%s 吃了 %s'%(name,food))
            q.task_done()
    
    if __name__ == '__main__':
        q = JoinableQueue()
        p1 = Process(target=producer,args=(q,'泔水'))
        p1.start()
        p2 = Process(target=producer, args=(q, '骨头'))
        p2.start()
        c1 = Process(target=consumer, args=(q, 'alex'))
        c1.daemon = True
        c1.start()
        c2 = Process(target=consumer, args=(q, 'egon'))
        c2.daemon = True
        c2.start()
        c3 = Process(target=consumer, args=(q, 'jin'))
        c3.daemon = True
        c3.start()
    
        p1.join()  # 等待p1执行完毕
        p2.join()  # 等待p2执行完毕

    3、ipc(inter-process-commnication内部进程交流)——

      pipe(管道):支持双向通信,数据不安全。

      首先来看管道是怎么用的

      

    from multiprocessing import  Pipe
    p1,p2=Pipe()
    p1.send('hello')        #一个发送,一个接收
    print(p2.recv())
    print('————————————————————————')
    p2.send('hihihi')
    p2.close()              #关闭p2发送端
    print(p1.recv())
    #print(p1.recv())     #放开的话,继续接收,会报错,报错类型:EOFError

    管道在多进程中的作用:主进程中发送到管道,然后在子进程中接收。

    应该特别注意管道端点的正确管理问题。如果是生产者或消费者中都没有使用管道的某个端点,就应将它关闭。这也说明了为何在生产者中关闭了管道的输出端,在消费者中关闭管道的输入端。如果忘记执行这些步骤,程序可能在消费者中的recv()操作上挂起。管道是由操作系统进行引用计数的,必须在所有进程中关闭管道后才能生成EOFError异常。因此,在生产者中关闭管道不会有任何效果,除非消费者也关闭了相同的管道端点。 

      

    from multiprocessing import Process
    from multiprocessing import Pipe,Lock
    def func(p):
        foo,son=p
        foo.close()             #只用son,就把foo给关了
        while True:
            try:
                print(son.recv())
            except EOFError:        #异常处理
                break
    
    if __name__ =='__main__':
        foo,son=Pipe()
        p=Process(target=func,args=((foo,son),))
        p.start()
        son.close()                #只用foo,把son给关了
        foo.send('hello')
        foo.send('hello')
        foo.send('hello')
        foo.send('heo')
        foo.close()

    pipe实现消费者生产者模型:

      

      

     1 from multiprocessing import Process,Pipe,Lock
     2 
     3 def consumer(p,name,lock):
     4     produce, consume=p
     5     produce.close()
     6     while True:
     7         # lock.acquire()
     8         baozi=consume.recv()
     9         # lock.release()
    10         if baozi:
    11             print('%s 收到包子:%s' %(name,baozi))
    12         else:
    13             consume.close()
    14             break
    15 
    16 def producer(p,n):
    17     produce, consume=p
    18     consume.close()
    19     for i in range(n):
    20         produce.send(i)
    21     produce.send(None)
    22     produce.send(None)
    23     produce.close()
    24 
    25 if __name__ == '__main__':
    26     produce,consume=Pipe()
    27     lock = Lock()
    28     c1=Process(target=consumer,args=((produce,consume),'c1',lock))
    29     c2=Process(target=consumer,args=((produce,consume),'c2',lock))
    30     p1=Process(target=producer,args=((produce,consume),10))
    31     c1.start()
    32     c2.start()
    33     p1.start()
    34 
    35     produce.close()
    36     consume.close()
    37 
    38     c1.join()
    39     c2.join()
    40     p1.join()
    41     print('主进程')
    pipe实现消费者生产者模型

     4、Manager:是一个类,提供了可以进行数据共享的一个机制,提供了很多数据类型dict 、list、pipe(这些并不提供数据安全的支持)

    from multiprocessing import Process,Manager,Lock
    def work(dict,lock):
        lock.acquire()
        dict['count']-=1
        lock.release()
    
    if __name__ =='__main__':
        lock=Lock()
        m=Manager()        #要用Manager定义dict
        dict=m.dict({'count':100})
        l=[]
        for i in range(100):
            p=Process(target=work,args=(dict,lock))
            p.start()
            l.append(p)
        [p.join() for p in l]
        print(dict)

     5、进程池:类似与有一个池子(工作间),把进程(员工)放进去,进行工作。接下来是发任务,然后循环对任务进行工作。(进程池这个功能已经被实现了)。

    import os
    import time
    import random
    from multiprocessing import Pool
    from multiprocessing import Process
    def func(i):
        i+=1
    
    if __name__=='__main__':
        # p=Pool(5)                #1、带#的是另一种方法:用进程池
        # start=time.time()
        # p.map(func,range(1000))   #相当于target=func,args=next(iterable)
        # p.close()                 #是不允许再向进程池中添加任务
        # p.join()
        # print(time.time()-start)
        p = Process()                 #2、起进程的办法,太占内存,费时间:起进程的时候要分配资源,分配内存,耗费时间
        start=time.time()
        l=[]
        for i in range(100):
            p=Process(target=func,args=(i,))
            p.start()
            l.append(p)
        [i.join() for i in l]
        print(time.time()-start)

      

  • 相关阅读:
    Leetcode 283. Move Zeroes
    算法总结
    随机森林
    BRICH
    DBSCAN算法
    k-means算法的优缺点以及改进
    soket编程
    手电筒过河
    字符串反转
    URAL 1356. Something Easier(哥德巴赫猜想)
  • 原文地址:https://www.cnblogs.com/wangyuxing/p/8418622.html
Copyright © 2020-2023  润新知