Який найшвидший спосіб запустити сценарій?


22

Мені було цікаво, який найшвидший спосіб запустити скрипт, я читав, що різниця у швидкості між показом виводу скрипту на терміналі, перенаправленням його на файл чи, можливо /dev/null.

Тож якщо вихід не важливий, який найшвидший спосіб змусити сценарій працювати швидше, навіть якщо він мінімальний.

bash ./myscript.sh 
-or-
bash ./myscript.sh > myfile.log
-or-
bash ./myscript.sh > /dev/null


Порівнювати "переадресацію до звичайного файлу" та "переадресацію на / dev / null" мені здається дивним ...
el.pescado

Відповіді:


31

Термінали в наші дні повільніші, ніж раніше, головним чином тому, що відеокарти більше не дбають про двовимірне прискорення. Отже, друк на терміналі може уповільнити сценарій, особливо якщо йдеться про прокручування.

Отже, ./script.shце повільніше ./script.sh >script.log, що, в свою чергу, повільніше, ніж/script.sh >/dev/null , тому що останні пов'язані з меншою роботою. Однак від того, чи достатньо це має значення для будь-яких практичних цілей, залежить від того, який обсяг виходу вашого сценарію і наскільки швидкий. Якщо ваш сценарій пише 3 рядки і виходить, або якщо він друкує 3 сторінки кожні кілька годин, вам, ймовірно, не потрібно буде турбуватися з перенаправленнями.

Редагувати: Деякі швидкі (і повністю зламані) орієнтири:

  • У консолі Linux, 240x75:

    $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done)
    real    3m52.053s
    user    0m0.617s
    sys     3m51.442s
  • У xtermрозмірі 260x78:

    $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done)
    real    0m1.367s
    user    0m0.507s
    sys     0m0.104s
  • Перенаправлення на файл на диску Samsung SSD 850 PRO 512GB:

     $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done >file)
     real    0m0.532s
     user    0m0.464s
     sys     0m0.068s
  • Перенаправлення на /dev/null:

     $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done >/dev/null)
     real    0m0.448s
     user    0m0.432s
     sys     0m0.016s

6
@Kingofkech - це менше 200 ліній / секунду. Це не мало би великого значення. (Для порівняння, timeout 1 yes "This is a looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line"надрукує 100000+ рядків за одну секунду на моєму MBP.)
muru

4
@Kingofkech Якщо це сценарій, то відредагуйте файл та прокоментуйте рядок, який видає непотрібний вихід. Ви багато отримаєте, особливо якщо це зовнішня команда (не вбудована оболонка), виконана 3 мільйони разів ...
jimmij

2
Для вузької інтерпретації "раніше". Термінал vt220 набагато повільніше, ніж сьогоднішні емулятори терміналу. Крім того, робочі станції SUN Sparc (ті, які я використовував) мали дійсно повільну консоль, тому просто перенаправлення виводу у файл при компіляції більшого проекту пришвидшило б час компіляції.
Kusalananda

1
@Kusalananda Це правда, xterms на HP Apollo 30 років тому використовувався для сканування порівняно xtermsз HP-UX 20 років тому. Однак консоль Linux з відеокарткою Matrox від 15 років тому була повільнішою, ніж та сама консоль Linux із картою S3 20 років тому. А консоль Linux з буфером кадрів високої роздільної здатності на сучасній карті просто непридатна. :)
Satō Katsura

6
@Kingofkech Це приблизно 2400 bps. Деякі з нас насправді прожили роками з цією швидкістю. :)
Satō Katsura

14

Я інстинктивно погодився би з відповіддю Сат-Кацури; це має сенс. Однак протестувати досить просто.

Я перевіряв написання мільйона рядків на екран, запис (додавання) до файлу та переадресацію на /dev/null. Я перевіряв кожне з них по черзі, потім робив п'ять повторів. Це команди, які я використав.

$ time (for i in {1..1000000}; do echo foo; done)
$ time (for i in {1..1000000}; do echo foo; done > /tmp/file.log) 
$ time (for i in {1..1000000}; do echo foo; done > /dev/null)

Потім я побудував загальні рази нижче.

графік часу проти результату

Як бачите, припущення Сат-Кацури були правильними. Відповідно до відповіді Satō Katsura, я також сумніваюся, що обмежуючим фактором буде вихід, тому малоймовірно, що вибір результату суттєво вплине на загальну швидкість сценарію.

FWIW, моя оригінальна відповідь мала інший код, який мав файл додаватись і /dev/nullперенаправлятися всередину циклу.

$ rm /tmp/file.log; touch /tmp/file.log; time (for i in {1..1000000}; do echo foo >> /tmp/file.log; done) 
$ time (for i in {1..1000000}; do echo foo > /dev/null; done)

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

графік часу проти результату

У цьому випадку результати зворотні.


FWIW Я додав швидкий орієнтир до своєї відповіді. Зокрема, консоль Linux> у 200 разів повільніше, ніж an xterm, що, в свою чергу, в 3 рази повільніше /dev/null.
Satō Katsura

Ви також повинні протестувати з деяким обмеженням швидкості. Вихід OP становить близько 200 ліній / с.
муру

@muru Ви маєте на увазі друк рядка, зачекайте 1/200 секунд, а потім повторіть? Я можу спробувати, але я вважаю, що це будуть подібні результати, але просто знадобиться набагато більше часу, щоб сигнал подолав шум. Хоча, можливо, я можу відняти час очікування перед аналізом.
Sparhawk

@Sparhawk щось подібне. Я думаю, що на такому рівні випуску процесору буде достатньо часу для оновлення дисплея без уповільнення швидкості виходу. Коли програма не робить нічого, крім шпигування рядків без пауз, термінальні буфери заповнюються швидше, ніж дисплей може бути оновлений і створює вузьке місце.
муру

3

Ще один спосіб пришвидшити сценарій - використовувати більш швидкий інтерпретатор оболонки. Порівняйте швидкості циклу зайнятості POSIX , запускайте версії bash v4.4 , ksh v93u + dash 20120801 та v0.5.8 .

  1. bash:

    time echo 'n=0;while [ $n -lt 1000000 ] ; do \
                      echo $((n*n*n*n*n*n*n)) ; n=$((n+1)); 
                   done' | bash -s > /dev/null

    Вихід:

    real    0m25.146s
    user    0m24.814s
    sys 0m0.272s
  2. ksh:

    time echo 'n=0;while [ $n -lt 1000000 ] ; do \
                      echo $((n*n*n*n*n*n*n)) ; n=$((n+1)); 
                   done' | ksh -s > /dev/null

    Вихід:

    real    0m11.767s
    user    0m11.615s
    sys 0m0.010s
  3. dash:

    time echo 'n=0;while [ $n -lt 1000000 ] ; do \
                      echo $((n*n*n*n*n*n*n)) ; n=$((n+1)); 
                   done' | dash -s > /dev/null

    Вихід:

    real    0m4.886s
    user    0m4.690s
    sys 0m0.184s

Підмножина команд в bashі kshє назад сумісним з усіма команд в dash. bashСкрипт , який використовує тільки команди в цій підгрупі повинен працювати з dash.

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

Коли ви сумніваєтесь, проведіть тест ...


тож для того, щоб швидко пропустити свій скрипт bash, мені потрібно переписати їх у bash чи ksh?
Кінгофкех

@Kingofkech Можливо, що код, який ви написали для bash, легко виправити ksh або dash-код. Спробуйте просто змінити перекладача.
блі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.