• python3 进程间的通信(队列)Queue


     队列的简单使用,队列先进先出

    import queue  # 不能用于多进程之间的通讯,可以用于多线程间的通讯
    from multiprocessing import Queue  # 可以用于进程之间的数据共享
    
    q = Queue(3)  # 创建一个队列对象,队列长度为3
    q.put(1)
    q.put(2)
    q.put(3)
    # q.put(4)  # 当队列已满,继续放值,,会阻塞程序
    try:
        q.put_nowait(4)  # 等同于 q.put(4, False)
    except:
        print("队列已经满了.")
    
    print(q.get())
    print(q.get())
    print(q.get())
    # print(q.get())  # 当队列空了,继续取值,也会阻塞程序
    try:
        q.get_nowait()  # 等同于q.get(block=False)
    except:
        print("队列已经空了.")

     执行结果:

    队列已经满了.
    1
    2
    3
    队列已经空了.

    通过队列实现进程间的通信

    import time
    from multiprocessing import Process, Queue
    
    
    def func1(name, q):
        q.put(name)  # 向队列中放入数据
    
    
    def func2(name, q):
        data = q.get()
        print(f"我是{name},取出-->{data}")
    
    
    if __name__ == '__main__':
        que = Queue()  # 创建一个队列
        que.put("主进程")  # 主进程向队列放入数据
        p1 = Process(target=func1, args=("子进程1", que,))  # 创建第一个子进程
        p2 = Process(target=func2, args=("子进程2", que,))  # 创建第二个子进程
        p1.start()  # 开启第一个子进程
        p2.start()  # 开启第二个子进程
        time.sleep(1)
        print(f"我是主进程,取出-->{que.get()}")

    执行结果:

    我是子进程2,取出-->主进程
    我是主进程,取出-->子进程1

    告诉消费者,没数据了

    import time
    from multiprocessing import Process, Queue
    
    
    def func1(q: Queue):
        for i in range(10):
            time.sleep(0.5)
            q.put(str(i))
    
    
    def func2(q: Queue):
        while 1:
            time.sleep(0.5)
            data = q.get()
            if data is None:
                print("数据取完了")
                break
            else:
                print(data)
    
    
    if __name__ == '__main__':
        q = Queue()
        p1 = Process(target=func1, args=(q,))
        p2 = Process(target=func2, args=(q,))
        p1.start()
        p2.start()
        p1.join()
        q.put(None)

    执行结果:

    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    数据取完了

     进程间的通信(简单的生产者和消费者关系)

    import multiprocessing
    
    
    def inputQ(queue, num):
        queue.put(num)
        print(f"put-->{num}")
    
    
    def outputQ(queue, num):
        info = queue.get()
        print(f"{num} get-->{info}")
    
    
    if __name__ == '__main__':
        multiprocessing.freeze_support()
        queue = multiprocessing.Queue(3)
        in_lst = []
        out_lst = []
        for i in range(10):
            p = multiprocessing.Process(target=inputQ, args=(queue, i))
            p.start()
            in_lst.append(p)
    
        for i in range(10):
            p = multiprocessing.Process(target=outputQ, args=(queue, i))
            p.start()
            out_lst.append(p)
    
        [pp.join() for pp in in_lst]
        [pp.join() for pp in out_lst]

    执行结果:

    put-->0
    put-->2
    put-->1
    0 get-->0
    put-->3
    1 get-->2
    put-->4
    2 get-->1
    put-->5
    4 get-->3
    put-->6
    3 get-->4
    5 get-->5
    put-->7
    put-->9
    6 get-->6
    put-->8
    7 get-->7
    8 get-->9
    9 get-->8
    windows下,如果开启的进程比较多的话,程序会崩溃,为了防止这个问题,使用freeze_support()方法来解决.

    哈哈,本来看到这段代码的时候,我以为程序会因为队列满了,导致堵塞.

    没想到竟然正常执行完了.

    看下程序没有堵塞的原因(生产者消费者模型):

      生产者(put)消费者(get)模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力,并且我可以根据生产速度和消费速度来均衡一下多少个生产者可以为多少个消费者提供足够的服务,就可以开多进程等等,而这些进程都是到阻塞队列或者说是缓冲区中去获取或者添加数据。

     

    生产者消费者模型

    import time
    from multiprocessing import Process, JoinableQueue  # 适合多个生产者和消费者
    
    
    def producer(name, q: JoinableQueue):
        for i in range(3):
            time.sleep(0.5)
            q.put(f"{name}{i}")
        q.join()  # 等待消费者把队列中的事物都取完,让生产者等待消费者执行完毕,等待队列里的数据都task_done才能继续执行。
    
    
    def consumer(name, q: JoinableQueue):
        while 1:
            time.sleep(0.5)
            data = q.get()
            print(f"{name} 吃 {data}")
            q.task_done()  # 告诉生产者,我消费了一个
    
    
    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=("消费者1", q))
        c2 = Process(target=consumer, args=("消费者2", q))
        c1.daemon = True  # 守护进程,主进程结束,子线程跟着结束
        c2.daemon = True
        p1.start()
        p2.start()
        p3.start()
        c1.start()
        c2.start()
        p1.join()
        p2.join()
        p3.join()

     执行结果:

    消费者1 吃 馒头0
    消费者2 吃 包子0
    消费者1 吃 大饼0
    消费者2 吃 馒头1
    消费者1 吃 包子1
    消费者2 吃 大饼1
    消费者1 吃 馒头2
    消费者2 吃 包子2
    消费者1 吃 大饼2
    #参数介绍:
        maxsize是队列中允许最大项数,省略则无大小限制。    
      #方法介绍:
        JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
        q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
        q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止,也就是队列中的数据全部被get拿走了。
  • 相关阅读:
    奥展项目笔记12-批量下载文件
    深度学习笔记03-梯度下降和方向传播
    深度学习笔记02-高效计算基础(python)
    深度学习笔记01-数学基础
    解决Android Studio卡在Gradle:Resolve dependecies 'app:_debugCompile'问题
    Oracle DB , 计算各个用户/schema 的磁盘占用空间
    转载:删除github上文件夹的两种方式
    Win7无法保存共享帐户密码
    怎么做网线,网线水晶头接法和线序
    QQ Protect 的删除
  • 原文地址:https://www.cnblogs.com/lilyxiaoyy/p/10973675.html
Copyright © 2020-2023  润新知