Почему Exiftool медленный, слишком много памяти читает из стандартного ввода; быстрое, небольшое чтение с диска

Я вызываю exiftool для извлечения тегов XMP, таких как Description, из больших видео размером 5 ГБ и более. Мое приложение - Python, и я видел некоторые файлы, которые истощают память; Я вызываю это так:

fp = open('9502_UAS_2.mov', 'rb')
CMD = 'exiftool -api largefilesupport=1 -sort -a -S -G -struct -j -'
exiftool = subprocess.Popen(CMD.split(),
                            stdin=fp, 
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
(json_bytes, stderr) = exiftool.communicate()

Чтобы изолировать проблему, я пробовал варианты в интерфейсе командной строки. Это показывает, что чтение из файла на диске происходит быстро и использует мало ОЗУ, тогда как чтение из STDIN (воссоздание указателя файла, прочитанного выше) очень медленное и использует много ОЗУ (я удалил выходные метаданные JSON ниже для ясность):

time exiftool -api largefilesupport=1 -sort -a -S -G -struct -j 9502_UAS.mov
real    0m0.196s

time cat 9502_UAS.mov | exiftool -api largefilesupport=1 -sort -a -S -G -struct -j -
real    0m33.514s

'top' показал, что второй потребляет до 1,4 ГБ ОЗУ для этого видеофайла 5,1 ГБ.

Я хотел бы понять, почему чтение из STDIN происходит медленно и потребляет так много памяти, поэтому я могу следить за такими ограничениями, как нехватка памяти на моих серверах. Считывает ли exiftool последовательно весь поток STDIN буферизацию файла до тех пор, пока он не получит двоичную информацию, необходимую для анализа метаданных? Разве это не seek () - назад и вперед, чтобы найти то, что ему нужно?

И наоборот, почему он так быстро запускается с файлом на собственном диске? Использует ли exiftool файловую систему с отображением памяти для быстрого перехода к разделам файла, которые необходимо проанализировать?

В идеале я бы читал из STDIN, потому что реальным источником файла приложения является ведро AWS S3, и я не хочу копировать файл на локальный диск AWS EC2, если я могу этого избежать, поэтому любые подсказки, чтобы сделать чтение stdin эффективным, могли бы помочь .

Спасибо.


person Chris Shenton    schedule 13.12.2016    source источник


Ответы (1)


Итак, в этом примере вы передаете все содержимое stdin. Конечно, на это нужно время. Было бы лучше передать имя файла внешнему инструменту:

CMD = 'exiftool -api largefilesupport=1 -sort -a -S -G -struct -j {}'
exiftool = subprocess.Popen(CMD.format('9502_UAS_2.mov').split(),
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
json_bytes, stderr = exiftool.communicate()

При переходе к stdin сначала весь файл будет передан в программу, и только после того, как этот процесс будет завершен, процесс останавливается (независимо от того, что инструмент уже выполнил свою работу).

Когда файл находится на удаленном сервере, вам нужно либо запустить этот сценарий на этом сервере, скопировать файл в локальный файл, либо прочитать первые n байта файла и передать только их в exiftool. (Определение размера n в качестве упражнения ...)

person Graipher    schedule 13.12.2016
comment
Я надеялся, что exiftool сможет использовать seek () для перехода к нужным частям файла, а затем закрыть (), когда это будет сделано: по-видимому, нет. Мне пришлось использовать обходной путь копирования файла из AWS S3 в экземпляр AWS EC2, который работает медленно и требует от меня использования очень большого раздела диска в экземпляре, поскольку его невозможно читать из файлового потока; в основном, как вы показываете, Popen () читает из локально скопированного файла. Если чтение из stdin через поток не поддерживается функцией seek / close (), было бы неплохо, если бы exiftool расширил возможность чтения диапазона байтов через HTTP, как это делают MediaInfo и ffmpeg сейчас. - person Chris Shenton; 29.12.2016