Python mmap ctypes - 只读模式
我觉得我遇到了一个和这里描述的情况正好相反的问题。我有一个进程在写日志数据,而我想让第二个进程来读取这些数据,但我不希望第二个进程能够修改内容。这个文件可能会很大,而且我需要随机访问,所以我使用了Python的mmap模块。
如果我把mmap设置为可读写(给第二个进程),我可以顺利地创建一个ctypes对象,作为mmap对象的“视图”,使用from_buffer方法。从我简单看过的C代码来看,这似乎是一个类型转换,而不是复制,这正是我想要的。然而,如果我把mmap设置为只读(ACCESS_READ),就会出错,提示from_buffer需要写权限。
我觉得我想用ctypes的from_address()方法,这个方法似乎不需要写权限。我可能漏掉了什么简单的东西,但我不太确定如何获取mmap中某个位置的地址。我知道我可以使用ACCESS_COPY(这样写操作会在内存中显示,但不会保存到磁盘),但我更希望保持只读。
有什么建议吗?
3 个回答
我遇到了一个类似的问题(无法设置只读的内存映射),但我当时只使用了Python的mmap模块。在Linux上,Python mmap出现“权限被拒绝”
我不确定这对你是否有帮助,因为你不想让这个内存映射是私有的,对吧?
我遇到了同样的问题,我们需要使用 from_buffer 接口,并且想要只读的访问权限。根据 Python 的文档,https://docs.python.org/3/library/mmap.html 上说:“对 ACCESS_COPY 内存映射的赋值会影响内存,但不会更新底层文件。”如果你可以接受使用匿名文件作为支持,那么你可以使用 ACCESS_COPY。
举个例子:打开两个 cmd.exe 窗口或者终端,在一个终端里输入:
mm_file_write = mmap.mmap(-1, 4096, access=mmap.ACCESS_WRITE, tagname="shmem")
mm_file_read = mmap.mmap(-1, 4096, access=mmap.ACCESS_COPY, tagname="shmem")
write = ctypes.c_int.from_buffer(mm_file_write)
read = ctypes.c_int.from_buffer(mm_file_read)
try:
while True:
value = int(input('enter an integer using mm_file_write: '))
write.value = value
print('updated value')
value = int(input('enter an integer using mm_file_read: '))
#read.value assignment doesnt update anonymous backed file
read.value = value
print('updated value')
except KeyboardInterrupt:
print('got exit event')
在另一个终端里输入:
mm_file = mmap.mmap(-1, 4096, access=mmap.ACCESS_WRITE, tagname="shmem")
i = None
try:
while True:
new_i = struct.unpack('i', mm_file[:4])
if i != new_i:
print('i: {} => {}'.format(i, new_i))
i = new_i
time.sleep(0.1)
except KeyboardInterrupt:
print('Stopped . . .')
你会发现第二个进程在第一个进程使用 ACCESS_COPY 写入时并不会收到更新。
根据我查看的mmap .c代码,我觉得它不支持我想要的用法。而且,我发现它的性能真的很差——对我来说就是这样。我很好奇其他人看到的性能如何,但我发现用Python处理一个500MB的二进制文件大约需要40秒。这是先创建一个mmap,然后把位置转成一个ctype对象,用from_buffer()方法,再用这个ctypes对象来判断对象的大小,以便我能跳到下一个对象。我尝试在C++中直接做同样的事情,使用msvc。显然,在这里我可以直接转换成正确类型的对象,速度很快——不到一秒(这是在一个Core 2 Quad和SSD上)。
我确实发现我可以用以下代码获取一个指针:
firstHeader = CEL_HEADER.from_buffer(map, 0) #CEL_HEADER is a ctypes Structure
pHeader = pointer(firstHeader)
#Now I can use pHeader[ind] to get a CEL_HEADER object
#at an arbitrary point in the file
不过这并没有解决最初的问题——mmap并不是只读的,因为我还是需要在第一次调用时用from_buffer。在这种情况下,处理整个文件仍然需要大约40秒,所以看起来从指针转换成ctypes结构体的过程在拖慢速度。这只是我的猜测,但我觉得继续追踪这个问题也没什么太大价值。
我不确定我的计划是否能帮助其他人,但我打算根据mmap代码创建一个专门满足我需求的C模块。我想我可以利用快速的C代码来索引二进制文件,然后通过调用ctypes/python对象一次只暴露文件的小部分。祝我好运。
另外,顺便提一下,Python 2.7.2今天(2011年6月12日)发布了,其中一个更新是mmap代码的改进,这样你就可以用Python的长整型来设置文件偏移量。这让你可以在32位系统上使用mmap处理超过4GB的文件。有关更多信息,请查看问题#4681 这里