Python mmap ctypes - только для чтения - PullRequest
6 голосов
/ 09 июня 2011

Я думаю, что у меня есть противоположная проблема, как описано здесь .У меня есть один процесс записи данных в журнал, и я хочу, чтобы второй процесс его прочитал, но я не хочу, чтобы 2-й процесс мог изменять содержимое.Это потенциально большой файл, и мне нужен произвольный доступ, поэтому я использую модуль mmap в python.

Если я создаю mmap для чтения / записи (для 2-го процесса), у меня нет проблем с созданием ctypes.объект как «представление» объекта mmap с использованием from_buffer.Из беглого взгляда на c-код, похоже, что это приведение, а не копия, что я и хочу.Тем не менее, это ломается, если я делаю mmap ACCESS_READ, выдавая исключение, что from_buffer требует привилегий записи.

I думаю Я хочу использовать вместо этого метод ctypes from_address (), который не появляетсянужен доступ для записи.Я, вероятно, упускаю что-то простое, но я не уверен, как получить адрес местоположения в mmap.Я знаю, что могу использовать ACCESS_COPY (поэтому операции записи отображаются в памяти, но не сохраняются на диске), но я бы предпочел, чтобы все оставалось только для чтения.

Есть предложения?

Ответы [ 3 ]

0 голосов
/ 13 июня 2011

Хорошо, глядя на код mmap .c, я не верю, что он поддерживает этот вариант использования.Кроме того, я обнаружил, что производительность в значительной степени отстой - для моего случая использования.Мне было бы любопытно, какую производительность видят другие, но я обнаружил, что для обхода двоичного файла объемом 500 МБ в Python требуется около 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-кода для индексации двоичного файла, а затем выставлять только небольшие части файла за один раз посредством вызовов в объекты ctypes / python.Пожелайте мне удачи.

Также, как примечание, Python 2.7.2 был выпущен сегодня (6/12/11), и одним из изменений является обновление кода mmap, чтобы вы могли использоватьpython long для установки смещения файла.Это позволяет использовать mmap для файлов размером более 4 ГБ в 32-разрядных системах.См. Выпуск № 4681 здесь

0 голосов
/ 20 февраля 2019

Столкнулся с этой же проблемой, нам был нужен интерфейс 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 голосов
/ 09 июня 2011

Я столкнулся с подобной проблемой (не удалось настроить mmap только для чтения), но я использовал только модуль python mmap. Python mmap «В доступе отказано» в Linux

Я не уверен, что это вам поможет, так как вы не хотите, чтобы mmap был приватным?

...