Команда find работает медленно, когда я не направляю вывод в awk.

Вопрос или проблема

У меня есть скрипт, который я использовал много лет для составления списка некоторых каталогов, со следующими строками:

 ##Найти все сценарии для этого номера сектора

   find /gsgt/source/scenarios/AT_* -name ${current}"*" -type d | \
   awk -F"/" '{print $NF}'  > Sector_${current}_list.txt

   find /gsgt/source/scenarios/AT_* -name "3T${current}*" -type d | \
   awk -F"/" '{print $NF}'  >> Sector_${current}_list.txt

   find /gsgt/source/scenarios/AT_* -name "4T${current}*" -type d | \
   awk -F"/" '{print $NF}'  >> Sector_${current}_list.txt

   find /gsgt/source/scenarios/AT_* -name "Sector_${current}*" -type d | \
   awk -F"/" '{print $NF}'  >> Sector_${current}_list.txt`

Это дает мне список только имен каталогов. Команды выполняются за доли секунды. Недавно мы обнаружили необходимость начинать с полных путей в аналогичном скрипте. Я переписал раздел без передачи в awk следующим образом:

   ##Найти все сценарии для этого номера сектора, поместить их в список

   find /gsgt/source/scenarios/AT_* -name ${current}"*" -type d \
   > Sector_${current}_list.txt

   find /gsgt/source/scenarios/AT_* -name "3T${current}*" -type d \
   >> Sector_${current}_list.txt

   find /gsgt/source/scenarios/AT_* -name "4T${current}*" -type d \
   >> Sector_${current}_list.txt

   find /gsgt/source/scenarios/AT_* -name "Sector_${current}*" -type d \
   >> Sector_${current}_list.txt

Это дает мне тот же список с полными путями, и работает, но это занимает почти минуту для завершения. Оно ищет в той же структуре дерева, с теми же входными переменными.

Почему второй вариант, который кажется “проще”, так медленно работает?

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

Попробуйте это:

find /gsgt/source/scenarios/AT_* \( \
    -name "${current}*" -o \
    -name "3T${current}*" -o \
    -name "4T${current}*" -o \
    -name "Sector_${current}*" \
    \) -type d > Sector_${current}_list.txt

Что ж, я все еще не знаю точно, почему скрипт работал так медленно, когда я набрал ./myscript.sh (в нем указан shebang для ksh), но запуск его как “ksh ./myscript.sh” сделал все различие. Весь скрипт выполняется за примерно 30 секунд, вместо 8 минут.

Оба скрипта действительно вызывают find 4 раза, но проблема медленной работы второго скрипта не связана только с избыточностью в числе вызовов find.
Разница в производительности между двумя скриптами заключается в том, как обрабатывается вывод и в воспринимаемом влиянии обхода каталогов.

@delirehberi написал однострочник, который отлично справляется с задачей!

Ответ или решение

Сравнение быстродействия команд в Unix-подобных операционных системах показывает, насколько важна оптимизация не только самих команд, но и способа обработки их выводов. В данном случае мы разбираем два варианта выполнения команды find, и различия в производительности между ними поднимают важные темы, касающиеся управления ресурсами и оптимизации скриптов.

Проблема с производительностью

Ваша первая версия скрипта, использующая конвейер с awk, выполняется значительно быстрее, чем вторая версия, которая отправляет вывод find непосредственно в файл. Почему это происходит? Давайте рассмотрим несколько ключевых факторов.

  1. Потоковая обработка вывода: Когда вы используете awk для обработки вывода find, данные передаются в конвейере, что позволяет find и awk работать параллельно. find находит и передает директории, а awk сразу же обрабатывает каждую строку по мере ее поступления. Это позволяет сократить время ожидания и уменьшить нагрузку на диск.

  2. Частота входа-выхода на диск: При выполнении второй версии скрипта, каждый вызов find записывает результаты в файл, что требует больше операций ввода-вывода (I/O). Записи на диск являются более медленными по сравнению с обработкой данных в памяти, особенно если файловая система или диск загружены.

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

Оптимизация скрипта

Для достижения более эффективного результата, вы можете объединить все ваши условия поиска в один вызов find с помощью параметра -o (логическое "ИЛИ"). Например:

find /gsgt/source/scenarios/AT_* \( \
    -name "${current}*" -o \
    -name "3T${current}*" -o \
    -name "4T${current}*" -o \
    -name "Sector_${current}*" \
\) -type d > Sector_${current}_list.txt

Таким образом, вы снизите количество операций ввода-вывода и улучшите общую производительность скрипта.

Почему проблема исчезла при запуске через ksh?

Феномен, наблюдаемый при запуске вашего скрипта с использованием ksh ./myscript.sh, указывает на различия в интерпретаторах командной строки. Возможно, при запуске ./myscript.sh использовался другой интерпретатор (например, sh), который может иметь различные настройки производительности и оптимизации. Эти настройки могли повлиять на то, как выполнялись команды в скрипте. Различия в реализации этих интерпретаторов ведут к вот таким значительным изменениям во времени выполнения. Важно всегда проверять, какой интерпретатор используется для выполнения скриптов, если производительность важна.

Заключение

Работа с командами на Unix требует внимательного подхода к оптимизации не только самих команд, но и их взаимодействия друг с другом. Использование потоков обработки и сокращение количества обращений к файловой системе могут существенно сократить время выполнения. С учетом этих рекомендаций, вы сможете значительно повысить эффективность ваших скриптов и добиться желаемых результатов быстрее и надежнее.

Оцените материал
Добавить комментарий

Капча загружается...