Есть ли способ сделать этот однострочный лайнер быстрее?

контекст

У меня есть каталог из тысяч zip-файлов, датированных в форме YYYYMMDD_hhmmss.zip и каждый около 300K. Внутри каждого zip-файла около 400 xml-файлов каждый около 3K.

Проблема

Мне нужно иметь возможность искать и находить заданную строку в диапазоне дат zip-файлов.

Текущее (хотя и посредственное) решение

У меня есть следующий однострочный

 find /home/mydir/ -type f | sort | \ awk "/xml_20140207_000016.zip/,/xml_20140207_235938.zip/" | \ xargs -n 1 -P 10 zipgrep "my search string" 

Дело в том, что

  1. перечислить все файлы в тысячах файлов
  2. сортировать этот список файлов
  3. извлекать ряд файлов на основе заданных дат (эта команда awk выводит строки только после первой строки с совпадением и до этой второй строки)
  4. передать каждую строку результата, которая соответствует одному файлу zipgrep

Вопрос

Этот однострочный динамик работает очень медленно, даже с 10 процессами на 24-ядерной машине. Я считаю, что это медленное из-за команды zipgrep но я недостаточно zipgrep , чтобы знать, как его улучшить. Я не знаю, должен ли я быть, но я немного смущен тем, что коллега написал Java-инструмент, который работает быстрее, чем этот скрипт. Я бы хотел, если это возможно, отменить это. Тогда кто-нибудь знает, как сделать эту команду быстрее в этом контексте? Или улучшить какую-либо его часть?

3 Solutions collect form web for “Есть ли способ сделать этот однострочный лайнер быстрее?”

Есть часть, которую вы можете легко улучшить, но это не самая медленная часть.

 find /home/mydir/ -type f | sort | \ awk "/xml_20140207_000016.zip/,/xml_20140207_235938.zip/" 

Это несколько расточительно, потому что он сначала перечисляет все файлы, затем сортирует имена файлов и извлекает интересные. Команда find должна завершиться до начала сортировки.

Было бы быстрее перечислять только интересные файлы в первую очередь или, по крайней мере, как можно более мелкие надмножества. Если вам нужен фильтр с более мелким зерном по именам, чем find способен, подключитесь к awk, но не сортируйте: awk и другие по очереди фильтры могут обрабатывать строки один за другим, но сортировка требует полного ввода.

 find /home/mydir/ -name 'xml_20140207_??????.zip' -type f | \ awk 'match($0, /_[0-9]*.zip$/) && (time = substr($0, RSTART+1, RLENGTH-5)) && time >= 16 && time <= 235938' | xargs -n 1 -P 10 zipgrep "my search string" 

Частью, которая, очевидно, является субоптимальной, является zipgrep. Здесь нет простого способа повысить производительность из-за ограничений программирования оболочки. Сценарий zipgrep работает, перечисляя имена файлов в архиве и вызывая grep для содержимого каждого файла один за другим. Это означает, что zip-архив обрабатывается снова и снова для каждого файла. Программа Java (или Perl, или Python, или Ruby и т. Д.) Может избежать этого, обрабатывая файл только один раз.

Если вы хотите придерживаться программирования оболочки, вы можете попробовать установить каждый почтовый индекс вместо использования zipgrep.

 … | xargs -n1 -P2 sh -c ' mkdir "mnt$$-$1"; fuse-zip "$1" "mnt$$-$1"; grep -R "$0" "mnt$$-$1" fusermount -u "mnt$$-$1" ' "my search string" 

Обратите внимание, что параллелизм не поможет вам: ограничивающим фактором для большинства настроек будет пропускная способность ввода-вывода на диске, а не время процессора.

Я ничего не тестировал, но я думаю, что самым большим местом для улучшения было бы использование реализации zipgrep на более мощном языке.

Некоторые быстрые идеи;

  • Если все файлы находятся в одном каталоге, вы можете избавиться от find
  • Соглашение об имени вашего файла сортируется по дате, поэтому вам не нужен бит sort
  • С этими двумя частями в стороне, и если диапазон дат известен, вы можете использовать простой глобус имени файла вместо awk. Например (если ваша оболочка bash ):

    • Все файлы за один день

      echo xml_20140207_*.zip | xargs -n 1 -P 10 zipgrep "my search string"

    • Файлы, созданные с 15:00 до 18:00, либо с 07 февраля, либо 10 февраля 2014 года:

      echo xml_201402{07,10}_1{5..7}*.zip | xargs -n 1 -P 10 zipgrep "my search string"

Неясно, где ваше узкое место. Предположим, что это при чтении файлов. В зависимости от вашей системы хранения, перед ее обработкой быстрее читать весь файл. Это особенно верно для zipgrep который делает несколько zipgrep в файл: если файл не полностью в памяти, вы будете ждать, пока диск будет искать.

 find ... | parallel -j1 'cat {} >/dev/null; echo {}' | parallel zipgrep "my search string" 

Вышеуказанное будет cat один файл за раз и тем самым помещать его в кеш памяти, а затем запускать один zipgrep каждого процессора, который затем будет считываться из кеша памяти.

Я использовал RAID-системы, где вы получили 6-кратное ускорение за счет чтения 10 файлов параллельно, чем чтение 1 файла за раз или одновременное чтение 30 файлов. Если бы мне пришлось запустить выше в этой RAID-системе, я бы -j1 в -j10 .

Используя GNU Parallel вместо xargs вы xargs себя от смешивания вывода (см. http://www.gnu.org/software/parallel/man.html#DIFFERENCES-BETWEEN-xargs-AND-GNU-Parallel ).

  • Zgrep останавливается после первого совпадения, когда аргументы передаются из xargs
  • Когда вы должны использовать подоболочки vs `xargs`?
  • Комбинация ls, xargs и zcat приводит к дублированию суффиксов имени файла?
  • Различное поведение между find -exec и piping через xargs
  • Передача параметров mulitiple через xargs
  • Синтаксис командной строки для перенаправления аргументов?
  • curl page source из текстового файла, содержащего URL-адреса
  • Не удалось создать большой файл tar с трубкой и xargs
  • Использует xargs быстрее, чем не использует его?
  • почему не xarss правильно разбирает мой вход?
  • Предоставлять строки, хранящиеся в файле, в виде списка аргументов для команды?
  • Interesting Posts

    Virtualbox: ОС не может использовать новое расширенное дисковое пространство (.vdi)

    UEFI Защищенные ограничения на загрузку ключа?

    Список изменений файлов в определенной папке с огромным содержимым и несколькими уровнями подпапок (с достойной производительностью)

    Получите WiFi SSID при подключении

    Как выйти из панели MC SSH

    Как загрузить Debian в текстовый режим без использования GUI?

    соответствие строки awk из 2 столбцов

    Странное поведение samba и gvfs – половина каталогов / файлов случайно оказывается «отсутствующей»,

    Понимание туннелей SSH

    sudo в неинтерактивном скрипте

    Кто-нибудь когда-либо проверял правила брандмауэра OpenWrt по умолчанию?

    Как запустить новый графический интерфейс с пользовательской командой из tty1?

    Автоматическое открытие kwallet при входе в KDE

    Linux, GNU GCC, ld, скрипты версий и двоичный формат ELF. Как это работает?

    Ionice on cp – зачем мне нужен набор

    Linux и Unix - лучшая ОС в мире.