Python mmap ctypes - 只读

7
我认为我遇到了与这里描述的相反问题。 我有一个进程将数据写入日志,我希望第二个进程读取它,但我不希望第二个进程能够修改内容。 这可能是一个大文件,我需要随机访问,因此我正在使用Python的mmap模块。
如果我将mmap创建为读/写(对于第二个进程),那么我没有问题,可以使用from_buffer将ctypes对象创建为mmap对象的“视图”。 从对C代码的粗略查看来看,它似乎是一个强制转换而不是复制,这正是我想要的。 但是,如果我将mmap ACCESS_READ,则会中断此操作,抛出异常,指出from_buffer需要写权限。
我认为我应该改用ctypes from_address()方法,它似乎不需要写访问权限。 我可能错过了一些简单的东西,但我不确定如何获取mmap内部位置的地址。 我知道我可以使用ACCESS_COPY(因此写操作会显示在内存中,但不会保存到磁盘上),但我宁愿保持只读状态。
有什么建议吗?

如果你正在使用 Python mmap 模块,为什么需要创建一个 ctypes 对象? - tMC
日志不仅仅是文本,它包括我映射到ctypes结构类的数据结构。因此,我将把内存映射到各种结构类型,并使用它来访问子元素并决定如何处理日志的不同部分。 - Brett Stottlemyer
3个回答

1

从查看 mmap .c 代码来看,我不认为它支持这种用例。此外,我发现性能非常糟糕 - 对于我的用例而言。我很好奇其他人看到了什么样的性能,但我发现在 Python 中遍历一个 500 MB 的二进制文件需要大约 40 秒。这是创建一个 mmap,然后将位置转换为 ctype 对象并使用 ctypes 对象解密对象的大小,以便我可以跳到下一个对象。我尝试直接从 msvc 中使用 c++ 做同样的事情。显然,在这里我可以直接将其强制转换为正确类型的对象,并且速度很快 - 少于一秒钟(这是使用核心 2 四核和 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今天发布了(6/12/11),其中之一的更改是更新了mmap代码,以便您可以使用python long设置文件偏移量。这使您可以在32位系统上使用mmap处理超过4GB的文件。请参见问题#4681 here


1
遇到了同样的问题,我们需要使用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进行写操作时,第二个进程不会接收到更新。


0

我遇到了类似的问题(无法设置只读mmap),但我只使用了Python mmap模块。Linux上Python mmap“权限被拒绝”

我不确定这对你有任何帮助,因为你不想让mmap是私有的?


我在使用mmap打开和访问文件时没有任何问题。问题在于,如果缓冲区不可写,from_buffer()会抛出异常,因此我需要替代该调用的方法。 - Brett Stottlemyer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接