Влияние производительности Sed при использовании трубы вместо; - PullRequest
0 голосов
/ 08 мая 2018

Я пишу сценарий, и для вопросов читабельности я думаю о замене ';' в моем выражении sed трубой.

Например

sed 's/.*@@//;s/[[:space:]].*//;s/\(.*\\\).*/\1LATEST/'

станет

sed 's/.*@@//' | sed 's/[[:space:]].*//' | sed 's/\(.*\\\).*/\1LATEST/'

Я знаю, что у трубы есть цена, но я думаю, что ';' в седе есть и стоимость.

Может ли это быть эквивалентно? Если нет, насколько плохо это может быть в цикле тысяч итераций?

1 Ответ

0 голосов
/ 09 мая 2018

Это на самом деле интересный вопрос. Поскольку использование дополнительных конвейеров требует больше времени на обработку ЦП, но также работает быстрее для больших входов на многоядерных ЦП из-за распараллеливания.

Случай № 1: большие входы

Я использовал следующую команду для построения ввода и времени ваших команд:

time echo N | awk '{ for(i=0;i<$0;i++) print i"@@\n "i"\n"i"\\" }' | COMMAND > /dev/null

где N - целое число, указывающее AWK, как долго должен быть тестовый ввод, а COMMAND - команда (или конвейер), которую вы хотите рассчитать.

Я запускаю тесты для N = 10 000 000 на 2-ядерном компьютере:

Версия Single Sed:

time echo 10000000 | awk '{ for(i=0;i<$0;i++) print i"@@\n "i"\n"i"\\" }' | sed 's/.*@@//;s/[[:space:]].*//;s/\(.*\\\).*/\1LATEST/' > /dev/null

Результат:

real    1m26.714s
user    1m35.196s
sys     0m1.212s

Конвейерная версия sed:

time echo 10000000 | awk '{ for(i=0;i<$0;i++) print i"@@\n "i"\n"i"\\" }' | sed 's/.*@@//' | sed 's/[[:space:]].*//' | sed 's/\(.*\\\).*/\1LATEST/' > /dev/null

Результат:

real    0m56.280s
user    1m46.404s
sys     0m0.972s

Как вы можете видеть, даже если дополнительные конвейеры добавляют около 11 секунд дополнительного времени обработки (пользователь + sys), на самом деле команде требуется примерно на 30 секунд меньше реального времени для завершения, поскольку вывод каждой из трех команд sed выполняется обрабатывается следующим, пока он еще работает. На моей машине это приводит к тому, что реальное время обработки составляет почти половину процессорного времени, что указывает на эффективное использование обоих процессорных ядер.

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


Случай № 2: построчная обработка

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

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

time for ((i=1;i<=10000;i++)); do printf "$i@@\n $i\n$i\\ \n" | sed 's/.*@@//;s/[[:space:]].*//;s/\(.*\\\).*/\1LATEST/'; done > /dev/null

Результат:

real    0m27.430s
user    0m2.772s
sys     0m4.224s

Конвейерная седь:

time for ((i=1;i<=10000;i++)); do printf "$i@@\n $i\n$i\\ \n" | sed 's/.*@@//' | sed 's/[[:space:]].*//' | sed 's/\(.*\\\).*/\1LATEST/'; done > /dev/null

Результат:

real    0m57.274s
user    0m3.704s
sys     0m7.776s

Как видите, конвейерный sed работает более чем в два раза медленнее, чем одиночная команда sed.

Обратите внимание, что использование одного конвейера sed на большом входе (как в случае № 1) работает как минимум в 1000 раз быстрее, чем построчная обработка аналогичного ввода (как в случае № 2).

...