Какой самый быстрый способ запустить скрипт?

22

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

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

bash ./myscript.sh 
-or-
bash ./myscript.sh > myfile.log
-or-
bash ./myscript.sh > /dev/null
Kingofkech
источник
Сравнение «перенаправления в обычный файл» и «перенаправления в / dev / null» кажется мне таким странным ...
el.pescado

Ответы:

31

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

Следовательно ./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, 260х78:

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

     $ 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 (те, которые я использовал) имели очень медленную консоль, поэтому простое перенаправление вывода в файл при компиляции более крупного проекта значительно ускорило бы время компиляции.
Кусалананда
1
@Kusalananda Это правда, что xtermна HP Apollo 30 лет назад ползли по сравнению с xtermsHP-UX 20 лет назад. Однако консоль Linux с видеокартой Matrox 15 лет назад работала медленнее, чем та же консоль Linux с картой S3 20 лет назад. А консоль Linux с кадровым буфером высокого разрешения на современной карте просто непригодна. :)
Satō
6
@Kingofkech Это около 2400 бит / с. Некоторые из нас действительно жили годами с такими скоростями. :)
Satō
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)

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

график времени и производительности

В этом случае результаты меняются местами.

Sparhawk
источник
Я добавил быстрый тест в мой ответ. Примечательно, что консоль Linux работает в 200 раз медленнее, чем xtermв 3 раза медленнее, чем /dev/null.
Satō
Вы должны также проверить с некоторым ограничением скорости. Производительность OP составляет около 200 строк / с.
Муру
@muru Вы хотите напечатать строку, подождать 1/200 секунды, а затем повторить? Я могу попробовать, но я полагаю, что это будут аналогичные результаты, но потребуется гораздо больше времени, чтобы сигнал преодолел шум. Хотя, возможно, я могу вычесть время ожидания перед анализом.
Sparhawk
@ Sparhawk что-то в этом роде. Я думаю, что на этом уровне производительности у CPU будет достаточно времени для обновления дисплея без замедления скорости вывода. Когда программа ничего не делает, только выдает строки без паузы, буферы терминала заполняются быстрее, чем может быть обновлено отображение, и создает узкое место.
Муру
3

Другой способ ускорить работу скрипта - использовать более быстрый интерпретатор оболочки. Сравните скорости занятого цикла POSIX , работающего под bash v4.4 , ksh v93u + 20120801 и dash 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
@Kingofkech Может быть, код, который вы написали для bash, является легко корректным кодом ksh или dash. Попробуйте просто сменить переводчика.
ло