Низкая производительность отчета
Я использую reportlab, чтобы преобразовать большую библиотеку (простой текст на русском языке) в формат PDF. Когда исходный файл достаточно мал (скажем, около 10-50 кБ), он работает нормально. Но если я пытаюсь конвертировать большие тексты (более 500 КБ), потребуется много времени, чтобы продолжить работу отчета. Кто-нибудь знает в чем может быть проблема?
BYTES_TO_READ = 10000
def go(text):
doc = SimpleDocTemplate("output.pdf")
Story = [Spacer(1, 2*inch)]
style = styles["Normal"]
p = Paragraph(text, style)
Story.append(p)
doc.build(Story)
def get_text_from_file():
source_file = open("book.txt", "r")
text = source_file.read(BYTES_TO_READ)
source_file.close()
return text
go(get_text_from_file())
Итак, когда я пытаюсь установить BYTES_TO_READ
от 200 до 300 тысяч (т. е. просто чтобы увидеть, что происходит, не читая всю книгу, а только ее часть) - это занимает ОГРОМНОЕ количество времени
1 ответ
Позвольте мне в предисловии сказать, что у меня совсем нет опыта работы с reportlab. Это всего лишь общее предложение. Это также не касается того, как именно вы должны анализировать и форматировать текст, который вы читаете, в правильные структуры. Я просто продолжаю использовать Paragraph
класс для написания текста.
С точки зрения производительности, я думаю, что ваша проблема связана с попыткой прочитать огромную строку один раз и передать эту огромную строку в виде одного абзаца в reportlab. Если подумать, какой абзац на самом деле составляет 500 Кбайт?
То, что вы, вероятно, захотите сделать, это прочитать небольшими порциями и собрать свой документ:
def go_chunked(limit=500000, chunk=4096):
BYTES_TO_READ = chunk
doc = SimpleDocTemplate("output.pdf")
Story = [Spacer(1, 2*inch)]
style = styles["Normal"]
written = 0
with open("book.txt", "r") as source_file:
while written < limit:
text = source_file.read(BYTES_TO_READ)
if not text:
break
p = Paragraph(text, style)
Story.append(p)
written += BYTES_TO_READ
doc.build(Story)
При обработке всего 500 Кбайт:
%timeit go_chunked(limit=500000, chunk=4096)
1 loops, best of 3: 1.88 s per loop
%timeit go(get_text_from_file())
1 loops, best of 3: 64.1 s per loop
Опять же, очевидно, что это просто разделение вашего текста на произвольные абзацы размером с BYTES_TO_READ
значение, но не сильно отличается от одного огромного абзаца. В конечном счете, вы можете захотеть проанализировать текст, который вы читаете, в буфер и определить свои собственные абзацы, или просто разбить на строки, если это формат вашего исходного источника:
def go_lines(limit=500000):
doc = SimpleDocTemplate("output.pdf")
Story = [Spacer(1, 2*inch)]
style = styles["Normal"]
written = 0
with open("book.txt", "r") as source_file:
while written < limit:
text = source_file.readline()
if not text:
break
text = text.strip()
p = Paragraph(text, style)
Story.append(p)
written += len(text)
doc.build(Story)
Спектакль:
%timeit go_lines()
1 loops, best of 3: 1.46 s per loop