Скрипт bash; оптимизация скорости обработки

10

Мне было интересно, есть ли общие рекомендации по оптимизации скриптов Bash.

  • Например, удобнее писать циклы, чем строки команд, но быстрее ли это обрабатывать в системе? Пример:

    for i in a b c; do echo $i; done
    
    echo a
    echo b
    echo c
  • Иногда люди представляют разные решения для одной и той же проблемы. Так , например, sed, cut, awk, и echoвсе способны лишить цифры из строки. Мне было интересно, если вы можете сказать, что чем меньше цифр кода, тем быстрее, если вы используете:

    1. та же команда, например

      STRING=abc.def
      echo ${STRING} | sed 's/.def//g'
      echo ${STRING} | sed '$s/....$//'
    2. разные команды, например

      STRING=abc.def
      echo ${STRING} | cut -d . -f 1
      echo ${STRING} | sed 's/.def//g'
Винсент
источник
2
В большинстве случаев я бы предпочел удобочитаемость, а не скорость.
Бернхард
1
а) Да, использование цикла for связано с дополнительными затратами, но это не имеет значения, б) старайтесь минимизировать внешние команды и просто заменять вещи изнутри bash. И если вам нужно оптимизировать сценарий оболочки, вы делаете что-то не так и должны рассмотреть вопрос об использовании языка с лучшей поддержкой профилировщика.
Ульрих Дангел
Регулярные выражения, как правило, менее эффективны с точки зрения производительности, чем любой другой выбор, поэтому, если вы видите способ сделать что-то без него (например, вырезать), используйте это. Конечно, это может повлиять на читабельность, если ваша способность к чтению ограничена регулярными выражениями;)
Златовласка

Ответы:

8

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

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

Мораль этой истории заключается в том, что если вам действительно нужно больше скорости, вам лучше использовать (полу) скомпилированный язык, такой как Perl или Python, который быстрее запускается для запуска, в котором вы можете написать многие из упомянутых операций. и не нужно вызывать внешние программы, и имеет возможность вызывать внешние программы или вызывать в оптимизированные модули C (или любые другие) для выполнения большей части работы. Вот почему в Fedora «сахар для системного администрирования» (по сути, GUI) написан на Python: может добавить приятный графический интерфейс без особых усилий, достаточно быстрый для таких приложений, иметь прямой доступ к системным вызовам. Если этого недостаточно, возьмите C ++ или C.

Но не ходите туда, если только вы не докажете, что выигрыш в производительности стоит потери гибкости и времени разработки. Скрипты оболочки не так уж плохи для чтения, но я содрогаюсь, когда вспоминаю некоторые скрипты, используемые для установки Ultrix, которые я однажды пытался расшифровать. Я сдался, слишком много «оптимизации сценариев оболочки» было применено.

vonbrand
источник
1
+1, но многие люди утверждают, что с большей вероятностью выигрыш в гибкости и времени разработки с использованием чего-то вроде python или perl или shell, а не потери. Я бы сказал, что используйте только сценарий оболочки, если это необходимо, или то, что вы делаете, требует большого количества специфических команд оболочки.
Златовласка
22

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

Единственный способ убедиться в этом - это сравнить его с вашим вариантом использования. Существуют некоторые общие правила, но они применяются только для типичных объемов данных в типичных приложениях.

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

  • Для внутренней обработки в оболочке ATT ksh является самым быстрым. Если вы делаете много строковых манипуляций, используйте ATT ksh. Дэш идет вторым; bash, pdksh и zsh отстают.
  • Если вам нужно часто вызывать оболочку для выполнения очень короткой задачи каждый раз, dash выигрывает из-за низкого времени запуска.
  • Запуск внешнего процесса требует времени, поэтому один конвейер со сложными частями быстрее, чем конвейер в цикле.
  • echo $fooмедленнее, чем echo "$foo", потому что без двойных кавычек он разбивается $fooна слова и интерпретирует каждое слово как шаблон подстановочного имени файла. Что еще более важно, такое поведение расщепления и сглаживания редко желательно. Поэтому не забывайте всегда ставить двойные кавычки вокруг подстановок переменных и подстановок команд: "$foo", "$(foo)".
  • Специализированные инструменты имеют тенденцию побеждать инструменты общего назначения. Например, такие инструменты, как cutили headмогут быть эмулированы sed, но sedбудут медленнее и awkмедленнее. Обработка строки оболочки выполняется медленно, но для коротких строк она в значительной степени превосходит вызов внешней программы.
  • Более продвинутые языки, такие как Perl, Python и Ruby, часто позволяют писать более быстрые алгоритмы, но у них значительно более высокое время запуска, поэтому они стоят только производительности для больших объемов данных.
  • По крайней мере, в Linux каналы работают быстрее, чем временные файлы.
  • Большинство сценариев оболочки используются для процессов, связанных с вводом / выводом, поэтому использование ЦП не имеет значения.

В сценариях оболочки редко возникает проблема с производительностью. Приведенный выше список является чисто ориентировочным; в большинстве случаев совершенно нормально использовать «медленные» методы, поскольку разница часто составляет долю процента.

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

Жиль "ТАК - перестань быть злым"
источник
2
Хотя pythonи rubyопределенно медленнее запускается, по крайней мере, в моей системе, perlзапускаться так же быстро, как bashи ksh. GNU awk значительно медленнее, чем GNU sed, особенно в локалях utf-8, но это не относится ко всем awk и всем seds. ksh93> dash> pdksh> zsh> bash не всегда так ясен. Некоторые снаряды лучше в некоторых вещах, чем другие, и победитель не всегда одинаков.
Стефан Шазелас
2
Re «вы должны получить много из ...» : если «вы» включает в себя , правда пользователей системы . С помощью сценариев оболочки в популярных пакетах Linux пользователи часто тратят на несколько порядков больше времени, чем экономит поспешный программист.
АРУ
2

Мы расширим здесь наш пример глобализации, чтобы проиллюстрировать некоторые характеристики производительности интерпретатора сценариев оболочки. Сравнивая bashи dashпереводчик для этого примера , где процесс порождал для каждого из 30000 файлов, показывают , что тир может форк wcпроцессов почти в два раза быстрееbash

bash-4.2$ time dash -c 'for i in *; do wc -l "$i"; done>/dev/null'
real    0m1.238s
user    0m0.309s
sys     0m0.815s


bash-4.2$ time bash -c 'for i in *; do wc -l "$i"; done>/dev/null'
real    0m1.422s
user    0m0.349s
sys     0m0.940s

Сравнение базовой скорости зацикливания без вызова wcпроцессов показывает, что зацикливание тире почти в 6 раз быстрее!

$ time bash -c 'for i in *; do echo "$i">/dev/null; done'
real    0m1.715s
user    0m1.459s
sys     0m0.252s



$ time dash -c 'for i in *; do echo "$i">/dev/null; done'
real    0m0.375s
user    0m0.169s
sys     0m0.203s

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

$ time find -type f -print0 | wc -l --files0-from=- | tail -n1
    30000 total
real    0m0.299s
user    0m0.072s
sys     0m0.221s

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

Украдено из распространенных ошибок сценария оболочки от Pádraig Brady.

Рахул Патил
источник
1
Общее правило: обработка дескриптора файла также стоит, так что уменьшите их количество. А не for i in *; do wc -l "$i">/dev/null; doneлучше делать for i in *; do wc -l "$i"; done>/dev/null.
Манатворк
@manatwork также обнулит вывод команды timecmd
Рахул Патил
@manatwork Хорошо ... сейчас Пожалуйста, также дайте мне вывод без вызова wc -l, проверьте, я обновил в публикации ваш вывод
Рахул Патил
Ну, предыдущие измерения были сделаны в меньшем каталоге. Теперь я создал один с 30000 файлами и повторил тесты: pastebin.com/pCV6QKp2
manatwork
Эти тесты не позволяют различать время запуска каждой оболочки. Тесты, сделанные изнутри каждой оболочки, будут лучше.
АРУ