Python mmap ctypes - 只读

时间:2011-06-09 14:31:59

标签: python ctypes mmap

我认为我遇到了与here所述相反的问题。我有一个进程将数据写入日志,我想要第二个进程来读取它,但我不希望第二个进程能够修改内容。这可能是一个大文件,我需要随机访问,所以我使用的是python的mmap模块。

如果我将mmap创建为读/写(对于第二个进程),我可以使用from_buffer将ctypes对象创建为mmap对象的“视图”。从粗略看一下c代码,看起来这是一个演员,而不是副本,这就是我想要的。但是,如果我创建了mmap ACCESS_READ,则会中断,抛出from_buffer需要写权限的异常。

我想使用ctypes from_address()方法,它似乎不需要写访问权限。我可能遗漏了一些简单的东西,但我不确定如何在mmap中获取该位置的地址。我知道我可以使用ACCESS_COPY(因此写操作会显示在内存中,但不会持久保存到磁盘上),但我宁愿保持只读。

有什么建议吗?

3 个答案:

答案 0 :(得分:0)

我遇到了类似的问题(无法设置只读mmap)但我只使用了python mmap模块。 Python mmap 'Permission denied' on Linux

我不确定这对你有什么帮助,因为你不希望mmap是私有的吗?

答案 1 :(得分:0)

好的,从查看mmap .c代码,我不相信它支持这个用例。此外,我发现性能非常糟糕 - 对于我的用例。我很好奇其他人看到了什么样的性能,但我发现在Python中使用500 MB的二进制文件需要大约40秒。这是创建一个mmap,然后使用from_buffer()将位置转换为ctype对象,并使用ctypes对象解密对象的大小,以便我可以步入下一个对象。我尝试从msvc直接在c ++中做同样的事情。显然在这里我可以直接投射到一个正确类型的对象,它很快 - 不到一秒钟(这是一个核心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 long来设置文件偏移量。这使您可以在32位系统上使用mmap超过4GB的文件。请参阅问题#4681 here

答案 2 :(得分:0)

遇到同样的问题,我们需要from_buffer接口,并希望进行只读访问。来自python docs 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写入时,您将看到第二个进程没有收到更新