Python - mmap 共享内存

在程序运行过程中,可能遇到需要进程间或不同平台的语言之间进行信息交互,存在硬盘是一种解决方案但是速度太慢。python的mmap库提供了共享内存的实践方案可以完成信息在内存间交互。

简介

共享内存

内存共享是两个不同的进程共享内存的意思:同一块物理内存被映射到两个进程的各自的进程地址空间。这个物理内存已经被规定了大小(大小一定要比实际写入的东东大)以及名称。当需要写入时,找到内存名称,然后写入内存,等需要读取时候, 首先要知道你要读取多大(因为物理内存比你要读取的东东大,全部读取的话会读到一些“空”的东西),然后寻找对应名称的物理块,然后读取,就是这么简单。

mmap

mmap是一种虚拟内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。关于系统中mmap的理论说明可以看百度百科维基百科说明以及mmap函数介绍,这里的说明是针对在Python下mmap块的使用说明。

  • 官网文档:https://docs.python.org/2/library/mmap.html

使用方法

创建:创建并返回一个 mmap 对象
m = mmap.mmap(fileno, length[, flags[, prot[, access[, offset]]]])
  • fileno: 文件描述符,可以是file对象的fileno()方法,或者来自os.open(),在调用mmap()之前打开文件,不再需要文件时要关闭。
os.O_RDONLY   以只读的方式打开 Read only
os.O_WRONLY   以只写的方式打开 Write only
os.O_RDWR     以读写的方式打开 Read and write
os.O_APPEND  以追加的方式打开  
os.O_CREAT   创建并打开一个新文件
os.O_EXCL     os.O_CREAT| os.O_EXCL 如果指定的文件存在,返回错误
os.O_TRUNC    打开一个文件并截断它的长度为零(必须有写权限)
os.O_BINARY          以二进制模式打开文件(不转换)
os.O_NOINHERIT        阻止创建一个共享的文件描述符
os.O_SHORT_LIVED
os.O_TEMPORARY        与O_CREAT一起创建临时文件
os.O_RANDOM         缓存优化,但不限制从磁盘中随机存取
os.O_SEQUENTIAL   缓存优化,但不限制从磁盘中序列存取
os.O_TEXT           以文本的模式打开文件(转换)
  • **length:**要映射文件部分的大小(以字节为单位),这个值为0,则映射整个文件,如果大小大于文件当前大小,则扩展这个文件。

  • flags:MAP_PRIVATE:这段内存映射只有本进程可用;mmap.MAP_SHARED:将内存映射和其他进程共享,所有映射了同一文件的进程,都能够看到其中一个所做的更改;

  • **prot:**mmap.PROT_READ, mmap.PROT_WRITE 和 mmap.PROT_WRITE | mmap.PROT_READ。最后一者的含义是同时可读可写。

  • **access:**在mmap中有可选参数access的值有:

ACCESS_READ:读访问。
ACCESS_WRITE:写访问,默认。
ACCESS_COPY:拷贝访问,不会把更改写入到文件,使用flush把更改写到文件。
对象方法
  • m.close()

关闭 m 对应的文件;

  • m.find(str, start=0)

从 start 下标开始,在 m 中从左往右寻找子串 str 最早出现的下标;

  • m.flush([offset, n])

把 m 中从offset开始的n个字节刷到对应的文件中;

  • m.move(dstoff, srcoff, n)

等于 m[dstoff:dstoff+n] = m[srcoff:srcoff+n],把从 srcoff 开始的 n 个字节复制到从 dstoff 开始的n个字节,可能会覆盖重叠的部分。

  • m.read(n)

返回一个字符串,从 m 对应的文件中最多读取 n 个字节,将会把 m 对应文件的位置指针向后移动;

  • m.read_byte()

返回一个1字节长的字符串,从 m 对应的文件中读1个字节,要是已经到了EOF还调用 read_byte(),则抛出异常 ValueError;

  • m.readline()

返回一个字符串,从 m 对应文件的当前位置到下一个’\n’,当调用 readline() 时文件位于 EOF,则返回空字符串;

  • m.resize(n)

把 m 的长度改为 n,m 的长度和 m 对应文件的长度是独立的;

  • m.seek(pos, how=0)

同 file 对象的 seek 操作,改变 m 对应的文件的当前位置;

  • m.size()

返回 m 对应文件的长度(不是 m 对象的长度len(m));

  • m.tell()

返回 m 对应文件的当前位置;

  • m.write(str)

把 str 写到 m 对应文件的当前位置,如果从 m 对应文件的当前位置到 m 结尾剩余的空间不足len(str),则抛出 ValueError;

  • m.write_byte(byte)

把1个字节(对应一个字符)写到 m 对应文件的当前位置,实际上 m.write_byte(ch) 等于 m.write(ch)。如果 m 对应文件的当前位置在 m 的结尾,也就是 m 对应文件的当前位置到 m 结尾剩余的空间不足1个字节,write() 抛出异常ValueError,而 write_byte() 什么都不做。

使用示例

写入数据进共享内存
import ctypes
import mmap   # 核心库
import os
import struct
import numpy as np

# 创建内存映射文件句柄
fd = os.open('tmp/mmaptest', os.O_CREAT | os.O_TRUNC | os.O_RDWR)

# 建立内存缓冲区
# not win32
buf = mmap.mmap(fd, mmap.PAGESIZE, mmap.MAP_SHARED, mmap.PROT_WRITE)
# win32
buf = mmap.mmap(fd, 67108864, access = mmap.ACCESS_WRITE)

# 向buf中写入文件(二进制格式)
f = open('tmp/test2.bmp', 'rb').read()
buf.write(b'abc') # 写入字符串
buf.write(f) # 写入文件

# 当前指针位置
buf.tell()

# 移动指针到第11个字节
buf.seek(10)

# 将内存中的信息写入文件
buf.flush(0, 100)

# 关闭
buf.close()
从共享内存中读取数据
import mmap
import os
import struct
import cv2
import numpy as nps

# 创建内存映射文件句柄
fd = os.open('share_memory/tmp/mmaptest', os.O_RDONLY)

# 建立内存缓冲区
# not win32
buf = mmap.mmap(fd, mmap.PAGESIZE, mmap.MAP_SHARED, mmap.PROT_READ)
# win32
buf = mmap.mmap(fd, 67108864, access = mmap.ACCESS_READ)

# 读取并打印缓冲区中指定区域内存
string_length = 136
string, = struct.unpack('{}s'.format(string_length), buf[:string_length])
print(string)

# 将部分区域转换为需要的格式并使用(图像)
np_str = np.fromstring(buf[:string_length], dtype='uint8')
img = cv2.imdecode(np_str, flags=-1)

# 纯图像像素数据(仅需转换字符串为uint8)即可
data = np.fromstring(buf[:string_length], dtype='uint8')
img = data.reshape([10,10])

代码运行不会顺畅,仅提供使用思路

参考资料

  • https://docs.python.org/2/library/mmap.html
  • https://zhuanlan.zhihu.com/p/166330573
  • https://www.cnblogs.com/zhoujinyi/p/6062907.html
  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python提供了共享内存的实现方式,可以通过使用multiprocessing模块中的SharedMemory类来实现。 共享内存是一种进程间通信方式,允许两个不相关的进程访问同一段逻辑内存。这种方式非常高效,可以在进程之间共享和传递数据。共享内存的实现原理是不同进程之间连接同一段物理内存,在进程的地址空间中将这段物理内存连接起来,从而实现数据的共享。当某个进程向共享内存写入数据时,其他进程可以立即访问到这些数据的改动。 共享内存Python中的实现方式是使用SharedMemory类,通过该类可以创建共享内存对象,并在多个进程之间实现数据共享。首先,我们需要创建一个共享内存对象,可以通过指定共享内存的名称和大小来创建。然后,可以通过get_fd()方法获取共享内存的文件描述符,然后可以在其他进程中使用该文件描述符来连接到同一段共享内存。在连接到共享内存后,就可以在不同的进程中读取和写入共享内存中的数据。 总结来说,Python中的共享内存提供了一种高效的进程间通信方式,可以在不同的进程之间实现数据的共享和传递。通过使用SharedMemory类,可以创建共享内存对象,并在多个进程之间实现数据的读取和写入。这种方法可以提高程序的性能和效率,特别是在需要进程间快速交换大量数据的情况下。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [python进程通信方式总结(三):共享内存](https://blog.csdn.net/submarineas/article/details/113824445)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [Python - mmap 共享内存](https://blog.csdn.net/zywvvd/article/details/122778874)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值