Почему в данном случае `sed` no op намного быстрее, чем` awk`

Если вы используете систему с инструментом dbus-monitor (1), вы можете запустить эту программу как демон, чтобы он мог отслеживать изменения адреса интерфейса . Не уверен, что это за сообщение, но что-то вроде:

dbus-monitor 'some-filtering-expression' |
while read -r line; do
    xargs /path/to/your/script "${line"}
done

Вы также можете позволить dbus-monitor работать в свободном режиме (без фильтров), чтобы наблюдать, что происходит, когда устанавливается ваше сетевое соединение.

4
23.03.2019, 13:35
2 ответа

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

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

авк

Во-первых, посмотрите на тест в примере awk:

NR==100001

и см. последствия этого вgprof(GNU awk 4.0.1):

  %   cumulative   self                self     total
 time   seconds   seconds      calls   s/call   s/call  name
 55.89     19.73    19.73          1    19.73    35.04  interpret
  8.90     22.87     3.14  500000000     0.00     0.00  cmp_scalar
  8.64     25.92     3.05 1000305023     0.00     0.00  free_wstr
  8.61     28.96     3.04  500105014     0.00     0.00  mk_number
  6.09     31.11     2.15  500000001     0.00     0.00  cmp_nodes
  4.18     32.59     1.48  500200013     0.00     0.00  unref
  3.68     33.89     1.30  500000000     0.00     0.00  eval_condition
  2.21     34.67     0.78  500000000     0.00     0.00  update_NR

~50% времени тратится на «интерпретацию», цикл верхнего -уровня для запуска кодов операций, полученных из проанализированного скрипта.

При каждом запуске теста (т.е. 5000 строк сценария *100000 строк ввода ), awkдолжно:

  • Получить встроенный -в переменной "NR"(update_NR).
  • Преобразование строки "100001"(mk_number).
  • Сравните их (cmp_nodes, cmp_scalar, eval_condition).
  • Отбросить все временные объекты, необходимые для сравнения (free_wstr,unref)

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

сед

Для сравнения, в sed«тест» гораздо более ограничен. Это может быть только один адрес, диапазон адресов или ничего (, когда команда стоит первой в строке ), а sedможет сказать по первому символу , является ли это командой. адрес или команду. В примере это

100001

...один числовой адрес. Профиль (GNU sed 4.2.2 )показывает

  %   cumulative   self                self     total
 time   seconds   seconds      calls   s/call   s/call  name
 52.01      2.98     2.98     100000     0.00     0.00  execute_program
 44.16      5.51     2.53 1000000000     0.00     0.00  match_address_p
  3.84      5.73     0.22                               match_an_address_p
[...]
  0.00      5.73     0.00       5000     0.00     0.00  in_integer

Опять же, ~50% времени находится на верхнем -уровне execute_program. В этом случае он вызывается один раз для каждой строки ввода, а затем перебирает проанализированные команды. Цикл начинается с проверки адреса, но это еще не все, что он делает в вашем примере (, см. далее ).

Номера строк во входном скрипте анализировались во время -компиляции(in_integer). Это нужно сделать только один раз для каждого номера адреса во входе, т.е. 5000 раз и не вносит существенного вклада в общее время работы.

Это означает, что проверка адреса, match_address_p, сравнивает только целые числа, которые уже доступны (через структуры и указатели ).

дополнительные sedулучшения

В профиле видно, что match_address_pзвонят 2 *5000 *100000 раз, т.е. дважды на сценарий -строка *ввод -строка. Это связано с тем, что за кулисами GNU sedобрабатывает команду «начать блок»

.
100001{...}

как обратная ветвь к концу блока

100001!b end;... :end

Это совпадение адреса завершается успешно в каждой строке ввода, вызывая переход к концу блока(}). Этот конец блока -не имеет связанного адреса, так что это еще одно успешное совпадение. Это объясняет, почему так много времени тратится на execute_program.

Так что выражение sedбыло бы еще быстрее, если бы в нем опускалось неиспользуемое ;bи полученное ненужное {...}, оставляя только 100001p.

  %   cumulative   self               self     total           
 time   seconds   seconds     calls   s/call   s/call  name    
 71.43      1.40     1.40 500000000     0.00     0.00  match_address_p
 24.49      1.88     0.48    100000     0.00     0.00  execute_program
  4.08      1.96     0.08                             match_an_address_p

Это вдвое сокращает количество вызовов match_address_p, а также сокращает большую часть времени, затрачиваемого на execute_program(, поскольку совпадение адреса никогда не удается ).

8
27.01.2020, 20:48

На самом деле приведенный выше скрипт не является noop для awk:

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

  • сканирование всех вхождений FS
  • разделение поля
  • обновление переменной NF

Если вы не используете эту информацию, впоследствии она просто отбрасывается.

Если разделитель полей не встречается в записи, awk все равно должен присвоить тексту значение $0 (, а в вашем случае и значение $1 ),и установите NF равным фактическому количеству полученных полей (1 в примере выше)

1
27.01.2020, 20:48

Теги

Похожие вопросы