Разница между чтением из файла и MongoDB GridFS?

Я разрабатываю веб-сайт с помощью Python Flask framework, который будет обрабатывать PDF-файлы. Я храню PDF-файлы в MongoDB, которая отлично работает, когда мне нужно предоставить их посетителям. Теперь мне нужно извлечь текст и изображения, для чего я использую библиотеку pdfminer. Когда я использую pdf2txt.py и предоставляю файл из файла системы, эта строка (контекст здесь) работает в значительной степени немедленно:

for page in PDFPage.get_pages(file('ticket.pdf', 'rb'), pagenos, maxpages=maxpages, password=password, caching=caching, check_extractable=True): pass

но когда я редактирую код, чтобы предоставить объект GridFS из моей MongoDB, вторая строка (поэтому после завершения извлечения) занимает около 8 секунд (результат идентичен приведенному выше коду):

document = UserDocument.objects.first()
for page in PDFPage.get_pages(document.file_, pagenos, maxpages=maxpages, password=password, caching=caching, check_extractable=True): pass

Меня это удивляет, потому что я предполагал, что получение файла из моей MongoDB или из файловой системы вернет одинаковый результат (в браузере он отображается одинаково), но, по-видимому, это не так. такой же.

Кто-нибудь знает, в чем разница между ними, из-за которой этот вызов занимает так много времени, и, что более важно, как я могу его решить? Все советы приветствуются!


person kramer65    schedule 23.12.2014    source источник


Ответы (1)


Чтобы ответить на мой собственный вопрос: оказывается, поскольку строки интернированы в Python, это означает, что любые манипуляции со строками создают новые строки, которые могут выйти из-под контроля, если у вас есть многомегабайтные строки (т.е. многократное копирование «остатка» строки в процесс в новую строку будет демонстрировать такое замедление).

Видимо это подчеркивает тот факт, что библиотека pdfminer написана плохо. Итак, у меня есть два варианта:

  1. Отредактируйте библиотеку pdfminer и отправьте запрос на включение.
  2. Запишите файл в файловую систему или в строковый буфер StringIO и прочитайте оттуда.

Хотя вариант 1 был бы лучшим вариантом, у меня нет ноу-хау этой библиотеки или времени, чтобы изучить это. Поэтому я выбрал вариант 2, используя строковый буфер:

document = UserDocument.objects.first()
fp = StringIO()
fp.write(document.file_.read())  # Also takes about 0.8 sec, but thats still faster than 8 seconds.
for page in PDFPage.get_pages(file('ticket.pdf', 'rb'), pagenos, maxpages=maxpages, password=password, caching=caching, check_extractable=True): pass

Теперь это занимает около 1 секунды, что, хотя и медленно, но пока работает. Если мы продвинемся дальше в процессе разработки, мы посмотрим, сможем ли мы разветвить и улучшить библиотеку pdfminer.

person kramer65    schedule 24.12.2014