最近发了个宏愿想写一个做企业金融研究的Python框架。拖出Python一看已经更新到了3.8,于是就发现了Python 3.8里新出现的模块:multiprocessing.shared_memory

随手写了个测试。生成一个240MB大小的pandas.DataFrame,然后转换成numpy.recarray。这个DataFarme里包括了datetime,整型和字符串类型的列。使用numpy.recarray的目的是为了保存dtype,这样才能在子进程中正确从共享内存里读数据。 我在子进程中简单地使用numpy.nansum来做计算。第一种方法是使用共享内存,第二种方法是直接将numpy.recarray作为参数传递给子进程。 下图为测试代码的输出。

可以看出,使用共享内存的第一种方法只使用了可以忽略不计的内存,并且2秒结束战斗。传参数的方法使用了1.8GB的内存,并且慢得要命,花费200多秒。当然这跟我使用的测试机是一台2017年的12寸MacBook 4-core i5 8G RAM(已停产)有可能,不过侧面也说明在数据足够大的时候,尽量避免没必要的复制和传递还是很有效的。

测试代码如下:

from multiprocessing.shared_memory import SharedMemory
from multiprocessing.managers import SharedMemoryManager
from concurrent.futures import ProcessPoolExecutor, as_completed
from multiprocessing import current_process, cpu_count
from datetime import datetime
import numpy as np
import pandas as pd
import tracemalloc
import timedef work_with_shared_memory(shm_name, shape, dtype):print(f'With SharedMemory: {current_process()=}')# Locate the shared memory by its nameshm = SharedMemory(shm_name)# Create the np.recarray from the buffer of the shared memorynp_array = np.recarray(shape=shape, dtype=dtype, buf=shm.buf)return np.nansum(np_array.val)def work_no_shared_memory(np_array: np.recarray):print(f'No SharedMemory: {current_process()=}')# Without shared memory, the np_array is copied into the child processreturn np.nansum(np_array.val)if __name__ == "__main__":# Make a large data frame with date, float and character columnsa = [(datetime.today(), 1, 'string'),(datetime.today(), np.nan, 'abc'),] * 5000000df = pd.DataFrame(a, columns=['date', 'val', 'character_col'])# Convert into numpy recarray to preserve the dtypesnp_array = df.to_records(index=False)del dfshape, dtype = np_array.shape, np_array.dtypeprint(f"np_array's size={np_array.nbytes/1e6}MB")# With shared memory# Start tracking memory usagetracemalloc.start()start_time = time.time()with SharedMemoryManager() as smm:# Create a shared memory of size np_arry.nbytesshm = smm.SharedMemory(np_array.nbytes)# Create a np.recarray using the buffer of shmshm_np_array = np.recarray(shape=shape, dtype=dtype, buf=shm.buf)# Copy the data into the shared memorynp.copyto(shm_np_array, np_array)# Spawn some processes to do some workwith ProcessPoolExecutor(cpu_count()) as exe:fs = [exe.submit(work_with_shared_memory, shm.name, shape, dtype)for _ in range(cpu_count())]for _ in as_completed(fs):pass# Check memory usagecurrent, peak = tracemalloc.get_traced_memory()print(f"Current memory usage {current/1e6}MB; Peak: {peak/1e6}MB")print(f'Time elapsed: {time.time()-start_time:.2f}s')tracemalloc.stop()# Without shared memorytracemalloc.start()start_time = time.time()with ProcessPoolExecutor(cpu_count()) as exe:fs = [exe.submit(work_no_shared_memory, np_array)for _ in range(cpu_count())]for _ in as_completed(fs):pass# Check memory usagecurrent, peak = tracemalloc.get_traced_memory()print(f"Current memory usage {current/1e6}MB; Peak: {peak/1e6}MB")print(f'Time elapsed: {time.time()-start_time:.2f}s')tracemalloc.stop()

值得一提的是,numpy.ndarraydtype一定不能是object,不然子进程访问共享内存的时候一定segfault,但如果在主进程里访问共享内存就没事。


补充更新一下,上面的测试代码work_with_shared_memory 函数里不能解引用np_array,比如print(np_array),不然会segfault。使用np_array.valnp_array.date则没有问题则是因为这两个column的dtype不是object。而np_array.character_coldtype在这个代码里是object

解决这个问题的办法也很简单,(踩坑无数次后),在to_records()里指定dtype。

np_array = df.to_records(index=False,column_dtypes={'character_col': 'S6'})

这里我们指定character_col为长度为6的字符串。 如果是unicode的话,可以将S6换成U6。 超出指定长度的字符串则会被truncate。

这样就不会有segfault了。重点就是不能有objectdtype

c++ 共享内存_Python3.8多进程之共享内存相关推荐

  1. Linux容器间共享内存,C++容器模板在共享内存中的使用

    本文用于探讨在共享内存中使用容器的好处,以及几种在共享内存中C++模板容器的方法. 1 为什么要在共享内存中使用模板容器? 为什么要避开普通内存而选择共享内存,那肯定是使用共享内存的优势: 共享内存可 ...

  2. 【Android 内存优化】Java 内存模型 ( Java 虚拟机内存模型 | 线程私有区 | 共享数据区 | 内存回收算法 | 引用计数 | 可达性分析 )

    文章目录 一. Java 虚拟机内存模型 二. 程序计数器 ( 线程私有区 ) 三. 虚拟机栈 ( 线程私有区 ) 四. 本地方法栈 ( 线程私有区 ) 五. 方法区 ( 共享数据区 ) 1. 方法区 ...

  3. python3多进程 queue 取值_【整理】python多进程之间共享queue | 勤奋的小青蛙

    默认情况下,使用multiprocess.Queue()只是在两个进程之间进行通信,如下示例: import multiprocessing, time def task(args): count = ...

  4. linux 内存一直在增加,linux – 缓存内存和共享内存总和超过总内...

    所有共享内存也计为缓存. 共享内存是在内部使用tmpfs实现的. tmpfs实现为页面缓存的瘦包装器,只是没有任何后备存储(除了tmpfs是可交换的). 男人自由不解释这个.至少在我的系统上(由pro ...

  5. mmap内存映射、system V共享内存和Posix共享内存

    linux内核支持多种共享内存方式,如mmap内存映射,Posix共享内存,以system V共享内存.当内核空间和用户空间存在大量数据交互时,共享内存映射就成了这种情况下的不二选择.它能够最大限度的 ...

  6. c++ fork 进程时 共享内存_c/c++ Linux 进程间通信------共享内存

    1. 什么是共享内存 共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区.进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是 ...

  7. linux共享内存示例,linux 进程间共享内存示例

    写入端: #include #include #include #include #include using namespace std; struct MappingDataType { int ...

  8. linux查看共享内存max,浅析Linux的共享内存与tmpfs文件系统

    浅析Linux的共享内存与tmpfs文件系统 前言 共享内存主要用于进程间通信,Linux有两种共享内存(Shared Memory)机制: (1)** System V shared memory( ...

  9. aix 进程占用内存_AIX 5L上的共享库内存占用量

    本文研究了共享库如何在32位AIX 5L™(5.3)上占用内存,并演示了以下命令: ps svmon slibclean 禁止 进程图 Genkld 风格 本文讨论了进程的虚拟地址空间,以及内核共享库 ...

最新文章

  1. 转 理论联系实践较好的JVM的理解
  2. 2017年9月19日
  3. Hive表与hdfs文件关联
  4. 用Ext 2.0 combobox 做的省份和城市联动选择框
  5. 给oracle用户赋权限导入导出,Oracle常用命令-用户、表空间、赋权限、导入导出...
  6. 2020年大厂职级薪资一览表
  7. 论文浅尝 | 基于深度序列模型的知识图谱补全
  8. 【JAVA基础篇】多线程
  9. Go的http库详解
  10. 锐捷 重启计算机,锐捷客户端反复显示重新启动的处理办法
  11. 光纤节点 劫持检测,细数宽带运营商常见的几种http劫持行为
  12. 计算机在开机时会进行自检遇到,电脑开机自检卡住了怎么办
  13. 读研整活笔记1:调研编译器solang
  14. 松翰单片机SN8P2711AD实现AD转换的C语言程序例子
  15. 全裸或半裸的大肚照国际接轨 细数女星大尺度斗艳孕照
  16. linux下解压文件丢失文件,Linux下解压文件
  17. C语言冒泡排序法,用函数形式实现。
  18. fatal: 无法访问 ‘https://gitlab.com/libeigen/eigen.git/‘:Failed to connect to gitlab.com port 443: 没有到主机
  19. 推荐一款网管软件P2P终结者
  20. 无胁科技-TVD每日漏洞情报-2022-7-31

热门文章

  1. 通过WAD和Docker热部署Java Enterprise
  2. maven 版本号插件_Maven内部版本号插件–用法示例
  3. js删除两个集合中共同元素_多个集合中的共同和独特元素
  4. 提升您的Hibernate引擎
  5. 图形处理:betweeness中心性– neo4j的密码与graphstream
  6. Java监视器绑定的超人
  7. MapReduce算法–二级排序
  8. 高级ZK:异步UI更新和后台处理–第1部分
  9. VisualVM:通过SSH监视远程JVM(是否为JMX)
  10. JVM:如何分析线程转储