python-- 多进程队列 Queue、生成者和消费者

简介: python-- 多进程队列 Queue、生成者和消费者

多进程队列 Queue


# 栈:先进后出(First In Last Out       简称 FILO)
# 队列: 先进先出(First In First Out   简称 FIFO)
# 
# 
# import queue  不能进行多进程之间的数据传输
# from multiprocessing import Queue   借助Queue解决生产者消费者模型
# 队列是安全的。自带锁
from multiprocessing import Queue
q = Queue(num)  # num 队列的最大长度,为一个数字
q.get()  # 阻塞等待获取数据,如果有数据直接获取,如果没有数据,阻塞等待
q.put()  # 阻塞,如果可以直接往队列中放数据,就直接放,如果不能放,就阻塞等待
q.get_nowait()  # 不阻塞,如果有数据直接获取,没有数据就报错
q.put_nowait()  # 不阻塞,如果可以继续往队列中放数据,就直接放,不能放就报错

案例

from multiprocessing import Queue
q = Queue(3)  # 队列的最大长度
q.put(123)
q.put("abc")
q.put([4, 5, 6])
print(q.get())
print(q.get())
print(q.get())

结果:

123
abc
[4, 5, 6]

正常执行,队列的长度为3,添加了三个,获取了三个

from multiprocessing import Queue
q = Queue(3)  # 队列的最大长度
q.put(123)
q.put("abc")
q.put([4, 5, 6])
q.put(999)
print(q.get())
print(q.get())
print(q.get())

执行到q.put(999)阻塞,程序一直在等

from multiprocessing import Queue
q = Queue(3)  # 队列的最大长度
q.put(123)
q.put("abc")
q.put([4, 5, 6])
q.put_nowait(999)
print(q.get())
print(q.get())
print(q.get())

执行到q.put(999)报错

from multiprocessing import Queue
q = Queue(3)  # 队列的最大长度
q.put(123)
q.put("abc")
q.put([4, 5, 6])
print(q.get())
print(q.get())
print(q.get())
print(q.get_nowait())  # queue.Empty

执行到print(q.get_nowait())报错


生产者和消费者


生产者消费者模型主要是为解耦,借助队列来实现生产者消费者模型

from multiprocessing import Queue, Process
from time import sleep
def consumer(q, name):
    while 1:
        info = q.get()
        if info:
            print('%s 拿走了%s' % (name, info))
        else:  # 当消费者获得队列中数据时,如果获得的是None,就是获得到了生产者不再生产数据的标识
            break  # 此时消费者结束即可
def producer(q, product):
    for i in range(5):
        info = '生产了' + product + '版的娃娃%s号' % str(i)
        q.put(info)
        print(info)
    q.put(None)  # 让生产者生产完数据后,给消费者一个不再生产数据的标识
if __name__ == '__main__':
    q = Queue(5)
    pro = Process(target=producer, args=(q, '波多小姐'))
    con = Process(target=consumer, args=(q, '苍老师'))
    pro.start()
    con.start()

结果:

生产了波多小姐版的娃娃0号
生产了波多小姐版的娃娃1号
生产了波多小姐版的娃娃2号
生产了波多小姐版的娃娃3号
生产了波多小姐版的娃娃4号
苍老师 拿走了生产了波多小姐版的娃娃0号
苍老师 拿走了生产了波多小姐版的娃娃1号
苍老师 拿走了生产了波多小姐版的娃娃2号
苍老师 拿走了生产了波多小姐版的娃娃3号
苍老师 拿走了生产了波多小姐版的娃娃4号

改版上版的生产者和消费者

from multiprocessing import Queue, Process
import time
def consumer(q, name, color):
    while 1:
        info = q.get()
        if info:
            print('%s %s 拿走了%s \033[0m' % (color, name, info))
        else:  # 当消费者获得队列中数据时,如果获得的是None,就是获得到了生产者不再生产数据的标识
            break  # 此时消费者结束即可
def producer(q, product):
    for i in range(20):
        info = product + '的娃娃%s号' % str(i)
        q.put(info)
if __name__ == '__main__':
    q = Queue(10)
    p_pro1 = Process(target=producer, args=(q, '波多小姐'))
    p_pro2 = Process(target=producer, args=(q, '苍老师'))
    p_pro3 = Process(target=producer, args=(q, '小泽老师'))
    p_con1 = Process(target=consumer, args=(q, '麻老师', '\033[31m'))
    p_con2 = Process(target=consumer, args=(q, '王老师', '\033[32m'))
    p_l = [p_con1, p_con2, p_pro1, p_pro2, p_pro3]
    [i.start() for i in p_l]
    # 父进程如何感知到生产者子进程不再生产数据了?
    p_pro1.join()
    p_pro2.join()
    p_pro3.join()
    q.put(None)  # 几个消费者就要接受几个结束标识
    q.put(None)

结果

麻老师 拿走了波多小姐的娃娃0号 
 麻老师 拿走了波多小姐的娃娃2号 
 麻老师 拿走了波多小姐的娃娃3号 
 麻老师 拿走了波多小姐的娃娃4号 
 王老师 拿走了波多小姐的娃娃1号  麻老师 拿走了波多小姐的娃娃5号 
 麻老师 拿走了波多小姐的娃娃6号 
 王老师 拿走了波多小姐的娃娃7号 
 麻老师 拿走了波多小姐的娃娃8号 
 王老师 拿走了波多小姐的娃娃9号 
 麻老师 拿走了波多小姐的娃娃10号 
 王老师 拿走了波多小姐的娃娃11号 
 麻老师 拿走了波多小姐的娃娃12号 
 王老师 拿走了波多小姐的娃娃13号 
 麻老师 拿走了波多小姐的娃娃14号 
 王老师 拿走了波多小姐的娃娃15号 
 麻老师 拿走了波多小姐的娃娃16号 
 王老师 拿走了波多小姐的娃娃17号 
 麻老师 拿走了波多小姐的娃娃18号 
 王老师 拿走了波多小姐的娃娃19号 
 麻老师 拿走了苍老师的娃娃0号 
 王老师 拿走了苍老师的娃娃1号 
 麻老师 拿走了苍老师的娃娃2号 
 王老师 拿走了苍老师的娃娃3号 
 麻老师 拿走了苍老师的娃娃4号 
 王老师 拿走了苍老师的娃娃5号 
 麻老师 拿走了苍老师的娃娃6号 
 王老师 拿走了苍老师的娃娃7号 
 麻老师 拿走了苍老师的娃娃8号 
 王老师 拿走了苍老师的娃娃9号 
 麻老师 拿走了苍老师的娃娃10号 
 王老师 拿走了苍老师的娃娃11号 
 麻老师 拿走了苍老师的娃娃12号 
 王老师 拿走了苍老师的娃娃13号 
 麻老师 拿走了小泽老师的娃娃0号 
 王老师 拿走了苍老师的娃娃14号 
 麻老师 拿走了小泽老师的娃娃1号 
 王老师 拿走了苍老师的娃娃15号 
 麻老师 拿走了苍老师的娃娃16号 
 王老师 拿走了苍老师的娃娃17号 
 麻老师 拿走了苍老师的娃娃18号 
 王老师 拿走了小泽老师的娃娃2号 
 麻老师 拿走了苍老师的娃娃19号 
 王老师 拿走了小泽老师的娃娃3号 
 麻老师 拿走了小泽老师的娃娃4号 
 王老师 拿走了小泽老师的娃娃5号 
 麻老师 拿走了小泽老师的娃娃6号 
 王老师 拿走了小泽老师的娃娃7号 
 麻老师 拿走了小泽老师的娃娃8号 
 王老师 拿走了小泽老师的娃娃9号 
 麻老师 拿走了小泽老师的娃娃10号 
 王老师 拿走了小泽老师的娃娃11号 
 麻老师 拿走了小泽老师的娃娃12号 
 王老师 拿走了小泽老师的娃娃13号 
 麻老师 拿走了小泽老师的娃娃14号 
 王老师 拿走了小泽老师的娃娃15号 
 王老师 拿走了小泽老师的娃娃16号 
 麻老师 拿走了小泽老师的娃娃17号 
 王老师 拿走了小泽老师的娃娃18号 
 麻老师 拿走了小泽老师的娃娃19号


在改版

from multiprocessing import Process, JoinableQueue
q = JoinableQueue()
def consumer(q, name, color):
    while 1:
        info = q.get()
        print('%s %s 拿走了%s \033[0m' % (color, name, info))
        q.task_done()
def producer(q, product):
    for i in range(20):
        info = product + '的娃娃%s号' % str(i)
        q.put(info)
    q.join()  # 记录了生产了20个数据在队列中,此时会阻塞等待消费者消费完队列中所有数据
if __name__ == '__main__':
    q = JoinableQueue(10)
    p_pro1 = Process(target=producer, args=(q, '波多小姐'))
    p_con1 = Process(target=consumer, args=(q, '苍老师', '\033[31m'))
    p_con1.daemon = True  # 把消费者进程设为守护进程
    p_con1.start()
    p_pro1.start()
    p_pro1.join()  # 主进程等待生产者进程结束

结果:

苍老师 拿走了波多小姐的娃娃0号 
 苍老师 拿走了波多小姐的娃娃1号 
 苍老师 拿走了波多小姐的娃娃2号 
 苍老师 拿走了波多小姐的娃娃3号 
 苍老师 拿走了波多小姐的娃娃4号 
 苍老师 拿走了波多小姐的娃娃5号 
 苍老师 拿走了波多小姐的娃娃6号 
 苍老师 拿走了波多小姐的娃娃7号 
 苍老师 拿走了波多小姐的娃娃8号 
 苍老师 拿走了波多小姐的娃娃9号 
 苍老师 拿走了波多小姐的娃娃10号 
 苍老师 拿走了波多小姐的娃娃11号 
 苍老师 拿走了波多小姐的娃娃12号 
 苍老师 拿走了波多小姐的娃娃13号 
 苍老师 拿走了波多小姐的娃娃14号 
 苍老师 拿走了波多小姐的娃娃15号 
 苍老师 拿走了波多小姐的娃娃16号 
 苍老师 拿走了波多小姐的娃娃17号 
 苍老师 拿走了波多小姐的娃娃18号 
 苍老师 拿走了波多小姐的娃娃19号

程序有3个进程,主进程和生产者进程和消费者进程。当主进程执行到p_pro1.join()时,主进程会等待生产进程结束

而生产进程中(q.join())会等待消费者进程把所有数据消费完,生产者进程才结束。

现在的状态就是主进程等待生产者进程结束,生产者进程等待消费者消费完所有数据

所以,把消费者设置为守护进程,当主进程执行完,就代表生产进程已经结束,也就代表消费者进程已经把队列中数据消费完

此时,主进程一旦结束,守护进程也就是消费者进程也就跟着结束。整个程序也就能正常结束了。


相关文章
|
14天前
|
算法 调度 UED
深入理解操作系统:进程调度与优先级队列
【10月更文挑战第31天】在计算机科学的广阔天地中,操作系统扮演着枢纽的角色,它不仅管理着硬件资源,还为应用程序提供了运行的环境。本文将深入浅出地探讨操作系统的核心概念之一——进程调度,以及如何通过优先级队列来优化资源分配。我们将从基础理论出发,逐步过渡到实际应用,最终以代码示例巩固知识点,旨在为读者揭开操作系统高效管理的神秘面纱。
|
8天前
|
并行计算 数据处理 调度
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
|
20天前
|
调度 iOS开发 MacOS
python多进程一文够了!!!
本文介绍了高效编程中的多任务原理及其在Python中的实现。主要内容包括多任务的概念、单核和多核CPU的多任务实现、并发与并行的区别、多任务的实现方式(多进程、多线程、协程等)。详细讲解了进程的概念、使用方法、全局变量在多个子进程中的共享问题、启动大量子进程的方法、进程间通信(队列、字典、列表共享)、生产者消费者模型的实现,以及一个实际案例——抓取斗图网站的图片。通过这些内容,读者可以深入理解多任务编程的原理和实践技巧。
43 1
|
27天前
|
Python
Python中的多线程与多进程
本文将探讨Python中多线程和多进程的基本概念、使用场景以及实现方式。通过对比分析,我们将了解何时使用多线程或多进程更为合适,并提供一些实用的代码示例来帮助读者更好地理解这两种并发编程技术。
|
1月前
|
数据挖掘 程序员 调度
探索Python的并发编程:线程与进程的实战应用
【10月更文挑战第4天】 本文深入探讨了Python中实现并发编程的两种主要方式——线程和进程,通过对比分析它们的特点、适用场景以及在实际编程中的应用,为读者提供清晰的指导。同时,文章还介绍了一些高级并发模型如协程,并给出了性能优化的建议。
31 3
|
2月前
|
存储 算法 前端开发
深入理解操作系统:进程调度与优先级队列算法
【9月更文挑战第25天】在操作系统的复杂世界中,进程调度是维持系统稳定运行的核心机制之一。本文将深入探讨进程调度的基本概念,分析不同的进程调度算法,并着重介绍优先级队列算法的原理和实现。通过简洁明了的语言,我们将一起探索如何优化进程调度,提高操作系统的效率和响应速度。无论你是计算机科学的初学者还是希望深化理解的专业人士,这篇文章都将为你提供有价值的见解。
|
2月前
|
负载均衡 Java 调度
探索Python的并发编程:线程与进程的比较与应用
本文旨在深入探讨Python中的并发编程,重点比较线程与进程的异同、适用场景及实现方法。通过分析GIL对线程并发的影响,以及进程间通信的成本,我们将揭示何时选择线程或进程更为合理。同时,文章将提供实用的代码示例,帮助读者更好地理解并运用这些概念,以提升多任务处理的效率和性能。
60 3
|
1月前
|
存储 Python
Python中的多进程通信实践指南
Python中的多进程通信实践指南
21 0
|
2月前
|
消息中间件 安全 Kafka
Python IPC机制全攻略:让进程间通信变得像呼吸一样自然
【9月更文挑战第12天】在编程领域,进程间通信(IPC)是连接独立执行单元的关键技术。Python凭借简洁的语法和丰富的库支持,提供了多种IPC方案。本文将对比探讨Python的IPC机制,包括管道与消息队列、套接字与共享内存。管道适用于简单场景,而消息队列更灵活,适合高并发环境。套接字广泛用于网络通信,共享内存则在本地高效传输数据。通过示例代码展示`multiprocessing.Queue`的使用,帮助读者理解IPC的实际应用。希望本文能让你更熟练地选择和运用IPC机制。
58 10
|
2月前
|
监控 Ubuntu API
Python脚本监控Ubuntu系统进程内存的实现方式
通过这种方法,我们可以很容易地监控Ubuntu系统中进程的内存使用情况,对于性能分析和资源管理具有很大的帮助。这只是 `psutil`库功能的冰山一角,`psutil`还能够提供更多关于系统和进程的详细信息,强烈推荐进一步探索这个强大的库。
43 1