Использование генератора для буферизованного анализа большого файла
У меня есть большой файл, который мне нужно проанализировать - и, поскольку он будет генерироваться из внешних запросов каждый раз, когда запускается скрипт, поэтому нет способа проанализировать его один раз и кэшировать результаты. Я хочу сохранить объем памяти и читать и анализировать только логические "куски" этого файла, все, что находится между открытым "продуктом" и закрывающей фигурной скобкой. Не уверен, что канонический путь в Python, но я попробовал следующее:
def read_chunk(file_name, pattern_open_line, pattern_close_line):
with open(file_name,"r") as in_file:
chunk = []
in_chunk = False
open_line = re.compile(pattern_open_line);
close_line = re.compile(pattern_close_line)
try:
for line in in_file:
line = line.strip()
if in_chunk:
chunk.append(line)
if close_line.match(line):
yield chunk
if open_line.match(line):
chunk = []
chunk.append(line)
in_chunk = True
continue
except StopIteration:
pass
def get_products_buffered(infile):
chunks = read_chunk(infile, '^product\s*$', '^\s*\}\s*')
products = []
for lines in chunks:
for line in lines:
if line.startswith('productNumber:'):
productNumber = line[len('productNumber:'):].strip().rstrip(';').strip('"')
products.append(productNumber)
continue
return products
def get_products_unbuffered(infile):
with open(infile) as f:
lines = f.readlines()
f.close()
products = []
for line in lines:
if line.startswith('productNumber:'):
productNumber = line[len('productNumber:'):].strip().rstrip(';').strip('"')
products.append(productNumber)
continue
return products
Я профилировал оба прогона, и пока небуферизованное чтение быстрее:
Buffered reading
Found 9370 products:
Execution time: 3.0031037185720177
Unbuffered reading
Found 9370 products:
Execution time: 1.2247122452647523
это также вызывает гораздо большее попадание в память, когда файл по существу читается в память:
Line # Mem usage Increment Line Contents
================================================
29 28.2 MiB 0.0 MiB @profile
30 def get_products_buffered(infile):
31 28.2 MiB 0.0 MiB chunks = read_chunk(infile, '^product\s*$', '^\s*\}\s*')
32 28.2 MiB 0.0 MiB products = []
33 30.1 MiB 1.9 MiB for lines in chunks:
против:
Line # Mem usage Increment Line Contents
================================================
42 29.2 MiB 0.0 MiB @profile
43 def get_products_unbuffered(infile):
44 29.2 MiB 0.0 MiB with open(infile) as f:
45 214.5 MiB 185.2 MiB lines = f.readlines()