Производительность sed
vs. tail
убрать первую строку файла
TL; DR
sed
очень мощный и универсальный, но именно это делает его медленным, особенно для больших файлов с большим количеством строк.
tail
делает только одну простую вещь, но она делает это хорошо и быстро, даже для больших файлов с множеством строк.
Для файлов малого и среднего размера sed
и tail
выполняются одинаково быстро (или медленно, в зависимости от ваших ожиданий). Однако для больших входных файлов (несколько МБ) разница в производительности значительно возрастает (на порядок для файлов в диапазоне сотен МБ) с tail
явно более высокими показателями sed
.
эксперимент
Общие препараты:
Наши команды для анализа:
sed '1d' testfile > /dev/null
tail -n +2 testfile > /dev/null
Обратите внимание, что /dev/null
каждый раз я отправляю выходные данные, чтобы устранить вывод терминала или запись в файл как узкое место в производительности.
Давайте настроим RAM-диск для устранения дискового ввода-вывода как потенциального узкого места. Лично у меня есть tmpfs
навесное устройство, /tmp
поэтому я просто разместил свой testfile
там для этого эксперимента.
Затем я однажды создаю случайный тестовый файл, содержащий определенное количество строк $numoflines
со случайной длиной строки и случайными данными, используя эту команду (обратите внимание, что она определенно не оптимальна, она становится действительно медленной примерно для> 2 миллионов строк, но кого это волнует, это не что мы анализируем)
cat /dev/urandom | base64 -w0 | tr 'n' '\n'| head -n "$numoflines" > testfile
О, кстати. мой тестовый ноутбук работает под управлением Ubuntu 16.04, 64-разрядная версия на процессоре Intel i5-6200U. Просто для сравнения.
Сроки больших файлов:
Настройка огромная testfile
:
Выполнение вышеуказанной команды с numoflines=10000000
получением случайного файла, содержащего 10M строк, занимающих чуть более 600 МБ - это довольно много, но давайте начнем с этого, потому что мы можем:
$ wc -l testfile
10000000 testfile
$ du -h testfile
611M testfile
$ head -n 3 testfile
qOWrzWppWJxx0e59o2uuvkrfjQbzos8Z0RWcCQPMGFPueRKqoy1mpgjHcSgtsRXLrZ8S4CU8w6O6pxkKa3JbJD7QNyiHb4o95TSKkdTBYs8uUOCRKPu6BbvG
NklpTCRzUgZK
O/lcQwmJXl1CGr5vQAbpM7TRNkx6XusYrO
Выполните запуски по времени с нашим огромным testfile
:
Теперь давайте сначала выполним однократный запуск обеих команд, чтобы оценить, с какими величинами мы работаем.
$ time sed '1d' testfile > /dev/null
real 0m2.104s
user 0m1.944s
sys 0m0.156s
$ time tail -n +2 testfile > /dev/null
real 0m0.181s
user 0m0.044s
sys 0m0.132s
Мы уже видим действительно четкий результат для больших файлов, tail
это на порядок быстрее, чем sed
. Но просто для удовольствия и чтобы убедиться, что нет никаких случайных побочных эффектов, имеющих большое значение, давайте сделаем это 100 раз:
$ time for i in {1..100}; do sed '1d' testfile > /dev/null; done
real 3m36.756s
user 3m19.756s
sys 0m15.792s
$ time for i in {1..100}; do tail -n +2 testfile > /dev/null; done
real 0m14.573s
user 0m1.876s
sys 0m12.420s
Вывод остается прежним, sed
неэффективно удалять первую строку большого файла, tail
следует использовать там.
И да, я знаю, что циклические конструкции Bash медленны, но мы делаем здесь лишь относительно немного итераций, и время, которое занимает простой цикл, не так существенно по сравнению с sed
/ tail
runtime.
Сроки небольших файлов:
Настройка небольшая testfile
:
Теперь для полноты давайте рассмотрим более распространенный случай, когда у вас есть небольшой входной файл в диапазоне кБ. Давайте создадим случайный входной файл numoflines=100
, который выглядит следующим образом:
$ wc -l testfile
100 testfile
$ du -h testfile
8,0K testfile
$ head -n 3 testfile
tYMWxhi7GqV0DjWd
pemd0y3NgfBK4G4ho/
aItY/8crld2tZvsU5ly
Выполните запуск по времени с нашим маленьким testfile
:
Исходя из опыта, мы можем ожидать, что время для таких маленьких файлов будет в пределах нескольких миллисекунд, давайте сразу сделаем 1000 итераций:
$ time for i in {1..1000}; do sed '1d' testfile > /dev/null; done
real 0m7.811s
user 0m0.412s
sys 0m7.020s
$ time for i in {1..1000}; do tail -n +2 testfile > /dev/null; done
real 0m7.485s
user 0m0.292s
sys 0m6.020s
Как видите, сроки очень похожи, толковать или удивляться особо нечему. Для небольших файлов оба инструмента одинаково хорошо подходят.
sed
он более переносим: «+2»tail
отлично работает на Ubuntu, который использует GNUtail
, но не работает на BSDtail
.