Баш сценарій; оптимізація швидкості обробки


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, але це не має значення. b) намагайтеся мінімізувати зовнішні команди та просто замінити речі з bash. І якщо вам доведеться оптимізувати скрипт оболонки, ви робите щось не так, і вам слід розглянути можливість використання мови з кращою підтримкою профілю.
Ульріх Дангель

Регулярні вирази, як правило, менш ефективні, ніж будь-який інший вибір, тому якщо ви бачите спосіб зробити щось без одного (наприклад, вирізати), використовуйте це. Звичайно, це може вплинути на читабельність, якщо ваша здатність до читання обмежена регулярними виразами;)
goldilocks

Відповіді:


8

Оболонки не здійснюють ніякої реорганізації коду, який їм передають, він просто інтерпретується один рядок за іншим (більше нічого не має сенсу в інтерпретаторі команд). Значна частина часу, проведеного оболонкою, припадає на лексичний аналіз / аналіз / запуск програм, що називаються.

Для простих операцій (як-от ті, що змінюють рядки в прикладах наприкінці запитання) я здивуюсь, якщо час для завантаження програм не перекриє жодної мізерної різниці швидкості.

Мораль історії полягає в тому, що якщо вам дійсно потрібна більша швидкість, вам краще скористатися (напів) складеною мовою, як Perl або Python, з якою швидше почати, для чого можна записати багато згаданих операцій безпосередньо і не потрібно викликати зовнішні програми, і він має можливість викликати зовнішні програми або зателефонувати в оптимізовані C (або будь-які інші) модулі, щоб виконати велику роботу. Ось чому в Fedora "цукор системного адміністрування" (GUI, по суті) написаний на Python: Можна додавати приємний графічний інтерфейс з не надто великими зусиллями, досить швидкий для таких додатків, мати прямий доступ до системних викликів. Якщо вам недостатня швидкість, візьміть C ++ або C.

Але не їдьте туди, якщо не зможете довести, що підвищення продуктивності варто втратити гнучкість та час розробки. Сценарії оболонки не надто погані для читання, але я здригаюся, коли згадую деякі сценарії, які використовувались для встановлення Ultrix, я колись намагався розшифрувати. Я здався, було застосовано занадто багато "оптимізації сценарію оболонки".


1
+1, але багато людей стверджують, що швидше за все виграш у гнучкості та часі розвитку, використовуючи щось на зразок python або perl vs. shell, а не втрату. Я б сказав, що використовуйте лише скрипт оболонки, якщо це необхідно, або те, що ви робите, передбачає велику кількість команд для оболонки.
goldilocks

22

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

Єдиний спосіб бути впевненим - це орієнтир для вашого випадку використання. Існують деякі загальні правила, але вони застосовуються лише для типових обсягів даних у типових програмах.

Деякі загальні правила, які можуть бути, але не можуть бути правдивими в будь-яких конкретних обставинах:

  • Для внутрішньої обробки в оболонці ATT ksh найшвидший. Якщо ви робите багато стринг-маніпуляцій, використовуйте ATT ksh. Тире приходить другим; bash, pdksh і zsh відстають.
  • Якщо вам потрібно часто викликати оболонку, щоб кожен раз виконувати дуже коротке завдання, тире виграє через низький час запуску.
  • Початок зовнішнього процесу коштує часу, тому швидше мати один трубопровід зі складними шматками, ніж трубопровід у циклі.
  • 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, але це не відповідає всім awks і всім седам. ksh93> dash> pdksh> zsh> bash не завжди так чітко вирізаний, як це. Деякі снаряди в деяких речах кращі, ніж інші, а переможець не завжди однаковий.
Стефан Шазелас

2
Повторно "вам доведеться багато виграти від ..." : якщо "ви" включає базу користувачів, правда. Завдяки скриптам оболонки в популярних Linux-пакетах користувачі часто колективно витрачають на кілька порядків більше часу, ніж заощаджує поспішний програміст.
agc

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.

Викрадені з поширених помилок сценарію оболонки Падрайга Брейді.


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, перевірте, чи я оновив у публікації ваш вихід
Rahul Patil

Ну, попередні вимірювання проводилися на меншому каталозі. Тепер я створив один із 30000 файлів і повторив тести: pastebin.com/pCV6QKp2
manatwork

Ці орієнтири не враховують різний час початку кожної оболонки. Показники, зроблені всередині кожної оболонки, були б краще.
agc
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.