Intereting Posts
Правильный способ настройки RAID в Linux Локальный список NS не соответствует списку родительских NS Локальные диски, обнаруженные как многолучевое устройство Как подсчитать наличие шаблона в строке Как печатать каждую строку файла столько раз, сколько в соответствии с номером в первом столбце Молчаливые ошибки диска и надежность обмена Linux Fedora 23: как сделать снимок экрана с окном контекстного меню, открытым на экране В чем смысл `shared` memory в команде` free` shell? Как извлечь конкретное поле из строк из файла на основе соответствия последующих строк Почему в некоторых дистрибутивах Linux есть / dev / ttyS0, ttyS1 и т. Д., Хотя новые компьютеры не имеют такого последовательного порта? Двойное SSH-туннелирование для общей папки SMB Есть ли способ отслеживать, что удаляет исполняемый флаг из файла? Freeradius не видит своего WAP-клиента Установить Debian Squeeze RAID 5? Создание логического тома из другого свободного места LV

Как я могу оптимизировать эту команду Unix?

Следующая команда занимает около 10 минут для вывода результата

find . -name "muc*_*_20160920_*.unl*" | xargs zcat | awk -F "|" '{if($14=="20160920100643" && $22=="567094398953") print $0}'| head 

Как я могу улучшить свою производительность?

Как отмечено в комментариях, zgrep – лучший выбор для таких задач с возможностью globstar, который позволяет использовать ** как all path inside the directory except hidden

 shopt -s globstar zgrep -m 10 '^\([^|]*|\)\{13\}20160920100643|\([^|]*|\)\{7\}567094398953' ./**muc*_*_20160920_*.unl* shopt -u globstar 

Это уже довольно оптимизировано. Трудно понять, что такое шея бутылки, не зная больше деталей, таких как:

  • тип хранилища (HD, SSD, сеть, RAIDed)
  • количество и средний размер совпадающих файлов
  • количество каталогов и других несогласованных файлов
  • количество полей в каждой строке
  • средняя длина линии

Вещи, которые вы можете сделать в любом случае:

  • replace -print | xargs -print | xargs с -exec cmd {} + или -print0 | xargs -r0 -print0 | xargs -r0 если ваш find / xargs поддерживает его. -print | xargs -print | xargs не только ошибочен, но и дороже, поскольку xargs необходимо расшифровать символы, чтобы узнать, какие из них являются пробелами, и сделать некоторую дорогостоящую обработку цитаты.
  • исправить локаль до C ( export LC_ALL=C ). Поскольку все символы, используемые здесь ( | и десятичные цифры для содержимого файла и латинских букв, период и подчеркивание для имен файлов), являются частью переносимой кодировки, если ваша кодировка – это в противном случае UTF-8 или какая-либо другая многобайтовая кодировка, переход на C с его однобайтовой кодировкой обеспечит много работы для find и awk .
  • упростите часть awk : awk -F "|" '$14 == "20160920100643" && $22 == "567094398953"' awk -F "|" '$14 == "20160920100643" && $22 == "567094398953"' .
  • поскольку вы подключаете вывод к head , вы можете отключить буферизацию вывода для awk чтобы как можно раньше вывести эти 10 строк. С gawk или mawk вы можете использовать fflush() для этого. Или вы можете добавить if (++n == 10) exit в awk .

Подводить итоги:

 (export LC_ALL=C find . -name "muc*_*_20160920_*.unl*" -exec zcat {} + | awk -F "|" '$14 == "20160920100643" && $22 == "567094398953" { print; if (++n == 10) exit}') 

Если CPU – это бутылочная горловина, в многоядерной системе GNU вы можете попробовать:

 (export LC_ALL=C find . -name "muc*_*_20160920_*.unl*" -print0 | xargs -r0P 4 -n 100 sh -c ' zcat "$@" | awk -F "|" "\$14 == "20160920100643" && \$22 == "567094398953" { print; fflush()}"' sh | head) 

Для запуска 4 zcat | awk zcat | awk параллельно на 100 партий файлов.

Если это 20160920100643 является 20160920100643 времени, вы можете захотеть исключить ранее измененные файлы. С GNU или BSD find , добавьте -newermt '2016-09-20 10:06:42' .

Если строки имеют большое количество полей, вы получаете штраф за awk разделяющий его и выделяющий так много полей $n . Использование подхода, который учитывает только первые 22 поля, может ускорить работу:

 grep -E '^([^|]*\|){13}20160920100643(\|[^|]*){7}\|567094398953(\||$)' 

вместо команды awk . С GNU grep добавьте параметр --line-buffered для вывода строк как можно раньше в параллельном подходе или -m 10 чтобы остановить после 10 совпадений в непараллельном.

Подводя итог, если CPU – это горлышко бутылки, и у вас в вашей системе есть как минимум 4 ядра процессора, и есть не менее 400 файлов muc *, и вы находитесь в системе GNU (где grep обычно значительно быстрее, чем GNU awk ):

 (export LC_ALL=C find . -name "muc*_*_20160920_*.unl*" -newermt '2016-09-20 10:06:42' -print0 | xargs -r0P 4 -n 100 sh -c ' zcat "$@" | grep --line-buffered -E \ "^([^|]*\|){13}20160920100643(\|[^|]*){7}\|567094398953(\||$)" ' sh | head) 

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

@ Ответ Стефана Чазеласа дает множество подробностей о том, как вы можете оптимизировать командный конвейер

 find . -name "muc*_*_20160920_*.unl*" | xargs zcat | awk -F "|" '{if($14=="20160920100643" && $22=="567094398953") print $0}'| head 

Я собираюсь предоставить другой способ приблизиться к проблеме, где вы фактически измеряете, где вы проводите больше всего времени. Когда вы найдете, где потрачено время, вы можете определить, что с этим делать. Если вы хотите улучшить свое 10-минутное время работы, оптимизация шага, который занимает 2 секунды, почти бесполезна.

Когда я смотрю на командный конвейер, меня привлекают три вещи:

  1. find . – Какова структура каталогов? Сколько файлов в каталоге? Является ли каталог локальным для системы, на которой выполняется команда? Удаленная файловая система будет намного медленнее.
  2. -name "muc*_*_20160920_*.unl*" – Насколько близки все имена файлов в структуре каталогов? Все ли они «близки» к названию, а сложный / интенсивный процессор подходит для соответствия? Поскольку каждый файл в дереве каталогов должен иметь свое имя, считанное с диска, и по сравнению с шаблоном.
  3. xargs zcatxargs не кажется, что это слишком большая проблема производительности, особенно по сравнению с проблемами find выше и zcat . Даже если это 10 000 или даже 10 000 000 имен файлов, время, используемое при передаче и анализе только имен, почти наверняка незначительно по сравнению с временем, проведенным для поиска имен, а затем открытия и распаковки всех файлов. Насколько велики файлы? Потому что вы декомпрессируете весь файл, соответствующий вашему шаблону имени файла find .

Как вы можете определить, что является главной проблемой производительности? Измерьте производительность каждой команды в конвейере. (См. https://stackoverflow.com/questions/13294554/how-to-use-gnu-time-with-pipeline для получения подробной информации о сроках создания всего конвейера.) Вы можете запустить следующие команды и посмотреть, сколько времени каждый шаг вносит на время обработки всего трубопровода:

/usr/bin/time find . – Это говорит о том, сколько времени требуется для запуска через дерево каталогов. Если это происходит медленно, вам нужна лучшая система хранения. Сбросьте кеш файловой системы [s], прежде чем синхронизировать это, чтобы получить наихудшее измерение, затем запустите тайм- find снова и посмотрите, сколько кеширования влияет на производительность. И если каталог не является локальным, попробуйте запустить команду в реальной системе, в которой находятся файлы.

/usr/bin/time find . -name "muc*_*_20160920_*.unl*" /usr/bin/time find . -name "muc*_*_20160920_*.unl*" – Это расскажет вам, сколько времени требуется для сопоставления файлов с именами файлов. Снова очистите кеш файловой системы [s] и запустите его дважды.

/usr/bin/time bash -c "find . -name 'muc*_*_20160920_*.unl*' | xargs zcat > /dev/null" – Это тот, который, как я подозреваю, является основным компонентом долгой работы вашего конвейера время. Если это проблема, то zcat ответом может быть zcat команд zcat на ответ Стефана zcat .

Продолжайте добавлять шаги от исходного конвейера команд к тестируемому, пока не найдете, где вы проводите большую часть своего времени. Опять же, я подозреваю, что это шаг zcat . Если это так, возможно, zcat , опубликованная @ Stéphane Chazelas, поможет.

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

Если шаг zcat является вашим основным узким местом производительности, и одновременное выполнение нескольких процессов zcat не помогает или фактически замедляет работу, ваш конвейер привязан к IO, и вам необходимо решить проблему, используя более быстрое хранилище.

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

Как указано, невозможно дать правильный ответ без каких-либо дополнительных подробностей.

 locate -0 -b -r '^muc.*_.*_20160920_.*.unl.*gz' | xargs -0 zcat | awk -F "|" '$14=="20160920100643" && $22=="567094398953"'| head 
  • 1: найти (если доступно) намного быстрее, чем ** или find ; Используемое регулярное выражение должно быть настроено …

  • 2 и 3: фильтр PO

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

Тем не менее, если местонахождение доступно, это приведет к очень впечатляющему ускорению.

Было бы интересно, если бы PO мог предоставить time ... различных решений