Как читать строки из файла mmapped?
Кажется, что интерфейс mmap поддерживает только readline().
Если я пытаюсь перебрать объект, я получаю символ вместо полных строк.
Каким будет метод "pythonic" для чтения файла mmap'ed по строке?
import sys
import mmap
import os
if (len(sys.argv) > 1):
STAT_FILE=sys.argv[1]
print STAT_FILE
else:
print "Need to know <statistics file name path>"
sys.exit(1)
with open(STAT_FILE, "r") as f:
map = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ)
for line in map:
print line # RETURNS single characters instead of whole line
Ответы
Ответ 1
Самый краткий способ перебора строк mmap
-
with open(STAT_FILE, "r+b") as f:
map_file = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ)
for line in iter(map_file.readline, b""):
# whatever
Обратите внимание, что в Python 3 параметр sentinel функции iter()
должен иметь тип bytes
, в то время как в Python 2 он должен быть str
(то есть ""
вместо b""
).
Ответ 2
Я изменил ваш пример так:
with open(STAT_FILE, "r+b") as f:
m=mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ)
while True:
line=m.readline()
if line == '': break
print line.rstrip()
Предложения:
- Не вызывайте
map
переменных, это встроенная функция. - Откройте файл в режиме
r+b
, как в примере с Python на странице справки mmap
. Он гласит: в любом случае вы должны предоставить дескриптор файла для файла, открытого для обновления. См. Http://docs.python.org/library/mmap.html#mmap.mmap. - Лучше не использовать
UPPER_CASE_WITH_UNDERSCORES
глобальных переменных UPPER_CASE_WITH_UNDERSCORES
, как указано в UPPER_CASE_WITH_UNDERSCORES
Имена глобальных переменных" по адресу https://www.python.org/dev/peps/pep-0008/#global-variable-names. В других языках программирования (например, C) константы часто пишутся в верхнем регистре.
Надеюсь это поможет.
Редактировать: я сделал несколько тестов времени на Linux, потому что комментарий сделал меня любопытным. Вот сравнение времени, сделанного на 5 последовательных прогонах для текстового файла 137 МБ.
Нормальный доступ к файлам:
real 2.410 2.414 2.428 2.478 2.490
sys 0.052 0.052 0.064 0.080 0.152
user 2.232 2.276 2.292 2.304 2.320
Доступ к файлу mmap
:
real 1.885 1.899 1.925 1.940 1.954
sys 0.088 0.108 0.108 0.116 0.120
user 1.696 1.732 1.736 1.744 1.752
Эти сроки не включают в себя выражение для print
(я исключил его). Следуя этим цифрам, я бы сказал, что доступ к файлам, отображенным в память, происходит немного быстрее.
Изменить 2: Использование python -m cProfile test.py
Я получил следующие результаты:
5432833 2.273 0.000 2.273 0.000 {method 'readline' of 'file' objects}
5432833 1.451 0.000 1.451 0.000 {method 'readline' of 'mmap.mmap' objects}
Если я не ошибаюсь, тогда mmap
работает немного быстрее.
Кроме того, кажется, что not len(line)
работает хуже, чем line == ''
, по крайней мере, так я интерпретирую вывод профилировщика.
Ответ 3
Ниже приведено краткое описание:
with open(STAT_FILE, "r") as f:
m = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ)
while True:
line = m.readline()
if line == "": break
print line
m.close()
Обратите внимание, что line
сохраняет новую строку, поэтому вы можете удалить ее. Это также причина, по которой if line == ""
делает правильную вещь (пустая строка возвращается как "\n"
).
Причина, по которой исходная итерация работает так, как она делает, заключается в том, что mmap
пытается выглядеть как файл, так и строка. Он выглядит как строка для целей итерации.
Я понятия не имею, почему он не может (или не хочет) предоставлять readlines()/xreadlines()
.
Ответ 4
32-разрядная версия Python 2.7 для Windows более чем в два раза быстрее для файла mmapped:
В 27 МБ, текстовом файле размером 509 Кб (моя функция 'parse' не интересна, в основном это просто readline() очень быстро):
with open(someFile,"r") as f:
if usemmap:
m=mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
else:
m=f
e.parse(m)
С MMAP:
read in 0.308000087738
Без MMAP:
read in 0.680999994278