Python多进程间通讯(包含共享内存方式)

文章目录

  • 1 通过非共享内存配合队列方式
  • 2 通过共享内存配合队列方式


注:本博文测试环境为Linux系统。


1 通过非共享内存配合队列方式

下面是一个常见的生产者与消费者的模式示例,这里分别启动了两个子进程,一个为生产者(producer)一个为消费者(consumer)。生产者负责生产Numpy的NDArray数据(这里为了体现进程间传递数据会耗时故创建的NDArray的shape比较大),然后将数据放入队列Queue。消费者监控队列Queue一旦有数据就取出并简单打印下shape信息和填充的Value信息。

import time
import multiprocessing as mp
from multiprocessing import Process, Queueimport numpy as npdef producer_task(queue: Queue):for i in range(10):data = np.full(shape=(1, 3, 2048, 2048), fill_value=i, dtype=np.float32)queue.put(data)time.sleep(0.1)# send exit signalqueue.put(None)print("producer exit.")def consumer_task(queue: Queue):while True:data = queue.get()if data is None:breakprint(f"get data shape:{data.shape}, fill value:{data[0][0][0][0]}")print("consumer exit.")def main():queue = Queue()producer = Process(target=producer_task, args=(queue,), name="producer")consumer = Process(target=consumer_task, args=(queue,), name="consumer")producer.start()consumer.start()producer.join()consumer.join()if __name__ == '__main__':mp.set_start_method("spawn")main()

执行以上代码终端输出以下内容:

get data shape:(1, 3, 2048, 2048), fill value:0.0
get data shape:(1, 3, 2048, 2048), fill value:1.0
get data shape:(1, 3, 2048, 2048), fill value:2.0
get data shape:(1, 3, 2048, 2048), fill value:3.0
get data shape:(1, 3, 2048, 2048), fill value:4.0
get data shape:(1, 3, 2048, 2048), fill value:5.0
get data shape:(1, 3, 2048, 2048), fill value:6.0
get data shape:(1, 3, 2048, 2048), fill value:7.0
get data shape:(1, 3, 2048, 2048), fill value:8.0
get data shape:(1, 3, 2048, 2048), fill value:9.0
producer exit.
consumer exit.

为了进一步看清进程之间传递数据的过程,这里使用viztracer工具进一步分析(直接通过pip install viztraver即可安装)。使用指令如下,其中main.py就是上面的代码内容。跑完后会在当前目录下生成一个result.json文件。

viztracer main.py

通过如下指令可视化result.json文件:

vizviewer result.json

在终端输入上述指令后,终端会提示你打开网页并进入http://localhost:9001,如果使用的是VSCODE IDE在右下角也会提示你打开浏览器。
在这里插入图片描述

在这里插入图片描述
可以看到生产者进程在将数据放入队列后会先进行ForkingPickler.dump即数据序列化的过程,大概耗时12ms。然后开始posix.write即开始将数据从一个进程传递到另一个进程,大概耗时34ms。最后在消费者进程进行_pickle.loads即数据的反序列化,大概耗时6ms。从生产者进程将数据放入队列到消费者进程拿到数据总耗时约53ms。从这个示例中可以看到,当在进程间传递的数据量很大时会很耗时。


2 通过共享内存配合队列方式

下面示例代码将传递的数据改为了共享内存的方式,这样可以大幅减小进程间数据传递的成本。这里主要是使用multiprocessing库中的shared_memory.SharedMemory对象。创建新的共享内存时需要将create参数设置为True(如果是复用已有的共享内存时设置为False),然后指定具体的size大小,该参数为数据的字节大小,比如要申请一块存放数据类型为float32shape(1, 3, 2048, 2048)的空间所需字节数为1 * 3 * 2048 * 2048 * 4float32为4个字节)。根据Python官方文档介绍,当一个进程不在使用该共享内存时应关闭指向共享内存的文件描述符/句柄,具体做法是调用共享内存对象的close方法。当某块共享内存不在需要时,需在最后一个使用到的进程中调用unlink方法显示释放掉(如果不调用该方法,共享内存会一直存在,如果后续再不断申请新的共享内存则会出现共享内存泄露的问题,或者当程序未正常退出时该共享内存块会成为僵尸共享内存?)。例如在当前示例中,生产者进程创建了共享内存并放入队列里后可调用close方法关闭当前进程指向共享内存的文件描述符/句柄,在消费者进程中拿到数据并消费完后除了调用close方法外还会调用unlink方法删除该共享内存。有关共享内存的详细介绍看查看Python官方文档:
https://docs.python.org/zh-cn/3/library/multiprocessing.shared_memory.html#multiprocessing.shared_memory.SharedMemory

import time
import multiprocessing as mp
from multiprocessing import Process, Queue, shared_memoryimport numpy as npdef producer_task(queue: Queue):for i in range(10):shm = shared_memory.SharedMemory(name=f"data_{i}",create=True,size=1 * 3 * 2048 * 2048 * 4)np_data = np.ndarray(shape=(1, 3, 2048, 2048), dtype=np.float32, buffer=shm.buf)np_data.fill(i)queue.put(shm.name)shm.close()time.sleep(0.1)# send exit signalqueue.put(None)print("producer exit.")def consumer_task(queue: Queue):while True:shm_name = queue.get()if shm_name is None:breakshm = shared_memory.SharedMemory(name=shm_name, create=False)np_data = np.ndarray(shape=(1, 3, 2048, 2048), dtype=np.float32, buffer=shm.buf)print(f"get data shape:{np_data.shape}, fill value:{np_data[0][0][0][0]}")shm.close()shm.unlink()print("consumer exit.")def main():queue = Queue()producer = Process(target=producer_task, args=(queue,), name="producer")consumer = Process(target=consumer_task, args=(queue,), name="consumer")producer.start()consumer.start()producer.join()consumer.join()if __name__ == '__main__':mp.set_start_method("spawn")main()

同样我们使用viztracer来看看进程间的通讯情况:
在这里插入图片描述

数据从生产者进程传递到消费者进程耗时为245us相比之前不使用共享内存方法的53ms,速度比值为53000/245≈216X,提升还是非常明显的。但是这有个很奇怪的现象我无法理解,就是在生产者进程中调用close方法用了1.8ms,而在消费者进程里调用close方法只用了15us,unlink用了8us,如果有知道的大神希望能帮忙解释下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/470494.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入理解接口测试:实用指南与最佳实践5.0(一)

✨博客主页: https://blog.csdn.net/m0_63815035?typeblog 💗《博客内容》:.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 📢博客专栏: https://blog.csdn.net/m0_63815035/cat…

2024.11.12_大数据的诞生以及解决的问题

大数据的诞生以及解决的问题 视频一:大数据诞生的背景原因:传统的数据处理架构无法满足海量的数据存储和计算需求 视频三:区分离线处理场景和实时处理场景视频五:传统的大数据与现代的大数据区别(离线场景)…

ML 系列: 第 24 节 — 离散概率分布(泊松分布)

目录 一、说明 二、固定时间间隔示例 三、固定间隔的示例 四、泊松分布的主要特征 五、示例 5.1 平均客户数的计算: 5.2 用于计算和绘制泊松分布的 Python 代码: 一、说明 泊松概率分布是一种离散概率分布,它表示在固定的时间或空间间隔内发生…

闯关leetcode——3174. Clear Digits

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/clear-digits/description/ 内容 You are given a string s. Your task is to remove all digits by doing this operation repeatedly: Delete the first digit and the closest non-digit cha…

机器情绪及抑郁症算法

🏡作者主页:点击! 🤖编程探索专栏:点击! ⏰️创作时间:2024年11月12日17点02分 点击开启你的论文编程之旅https://www.aspiringcode.com/content?id17230869054974 计算机来理解你的情绪&a…

【深圳大学】数据结构A+攻略(计软版)

1. 考试 1.1 形式 分为平时,笔试,机试三部分。其中: 平时占30%,包含平时OJ测验和课堂练习,注意这个可能会因老师的不同和课题组的新策略而改变。笔试占60%,是分值占比的主要部分。机试占10%。 1.2 题型…

Chrome使用IE内核

Chrome使用IE内核 1.下载扩展程序IE Tab 2.将下载好的IE Tab扩展程序拖拽到扩展程序界面,之后重启chrome浏览器即可

使用pytest+openpyxl做接口自动化遇到的问题

最近使用pytestopenpyxl做了个接口自动化的小项目,遇到了一些问题。 首先,使用pytest这个框架,主要是使用了pytest.fixture, pytest.mark.parametrize这两个fixture去做参数化,里面注入的数据是用openpyxl来实现的。 接口介绍&a…

IEC60870-5-104 协议源码架构详细分析

IEC60870-5-104 协议源码架构 前言一、资源三、目录层级一二、目录层级二config/lib60870_config.hdependencies/READMEexamplesCMakeLists.txtcs101_master_balancedcs104_client_asyncmulti_client_servertls_clienttls_server说明 make这些文件的作用是否需要导入这些文件&a…

TensorRT基础知识

github:https://github.com/NVIDIA/TensorRT 官网快速入门链接:Quick Start Guide :: NVIDIA Deep Learning TensorRT Documentation 引言: TensorRT 是 NVIDIA 推出的一个高性能深度学习推理库,专门用于优化和加速已经训练好的深度学习模型…

jenkins提交gitee后自动部署

jenkins中安装gitee插件 Gitee Plugin​​​​​​ 配置gitee WebHook 生成giteeHook密码 去gitee中配置webHook 输入jenkins中的url和生成的密码 当我们再提交后就可以自动部署 gitee官方配置

软件测试面试八股文(超详细整理)

请你说一说测试用例的边界 参考回答: 边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法。通常边界值分析法是作为对等价类划分法的补充,这种情况下,其测试用例来自等价类的边界。 常见的边界值 1)对16-bit 的整数而言 32…

【金融风控】特征评估与筛选详解

内容介绍 掌握单特征分析的衡量指标 知道 IV,PSI等指标含义 知道多特征筛选的常用方法 掌握Boruta,VIF,RFE,L1等特征筛选的使用方法 【理解】单特征分析 什么是好特征 从几个角度衡量:覆盖度,区分度,相关性,稳定…

链游系统定制化开发:引领游戏产业的新时代

在数字革命的浪潮中,链游(区块链游戏)作为一种新兴游戏形式,正重新定义游戏产业的发展方向。链游将区块链技术与传统游戏结合,使游戏体验更加公平透明,并赋予玩家真正的资产所有权。这一领域不仅为玩家带来…

2024 年 8 个最佳 API 设计工具图文介绍

8 个最佳 API 设计工具推荐,包括 Apifox、Postman、Swagger、Insomnia、Stoplight、Hoppscotch、RapidAPI和Paw。 详细介绍:2024 年 8 个最佳 API 设计工具推荐

知识库管理系统:企业数字化转型的加速器

在数字化转型的大潮中,知识库管理系统(KBMS)已成为企业提升效率和创新能力的关键工具。本文将探讨知识库管理系统的定义、企业建立知识库的必要性,以及如何快速搭建企业知识库。 知识库管理系统是什么? 知识库管理系统…

24/11/12 算法笔记<强化学习> Policy Gradient策略梯度

gradient的核心就是每次更新前要重新收集,每个阶段的actor是不一样的. 策略梯度算法的核心思想: 策略表示:首先,策略梯度方法需要一个策略,该策略能够根据当前的状态选择一个动作。这个策略通常由一个参数化的函数表示…

物理设备命名规则(Linux网络服务器 15)

Linux系统中的一切都是文件,硬件设备也不例外。既然都是文件,就必须有文件名称。系统内核中udev设备管理器会自动把硬件名称规范化起来,目的是让用户通过设备文件的名字可以大致了解设备属性以及分区信息。这对于陌生的设备来说特别方便。另外…

SciPy:Python 科学计算工具包的全面教程

SciPy:Python 科学计算工具包的全面教程 引言 在数据科学和科学计算的领域,Python 已经成为一种流行的编程语言。作为 Python 的核心库之一,SciPy 提供了高效的数值计算功能,是科学计算、工程和数学应用中不可或缺的工具。本文将…

SAP_MM_SD_PP_FICO_视频课程几乎免费送

朋友们,都已经是2024年了,SAP中国区都已经被合并到樱花国的亚太区了,SAP上海研发中心也陆续撤离中*,竟然还有朋友花上万RMB学习SAP,钱花了可以在挣,主要是那个视频课程一个模块下来就得上百个小时&#xff…