Wydajność sed
vs., tail
aby usunąć pierwszą linię pliku
TL; DR
sed
jest bardzo wydajny i wszechstronny, ale to powoduje, że działa wolno, szczególnie w przypadku dużych plików z wieloma liniami.
tail
robi tylko jedną prostą rzecz, ale ta robi dobrze i szybko, nawet dla większych plików z wieloma liniami.
Dla małych i średnich plików sed
i tail
działają podobnie szybko (lub wolno, w zależności od oczekiwań). Jednak w przypadku większych plików wejściowych (wiele MB) różnica wydajności znacznie rośnie (rząd wielkości dla plików w zakresie setek MB), przy tail
wyraźnie lepszych wynikach sed
.
Eksperyment
Ogólne przygotowania:
Nasze polecenia do analizy to:
sed '1d' testfile > /dev/null
tail -n +2 testfile > /dev/null
Zauważ, że przesyłam dane wyjściowe za /dev/null
każdym razem, aby wyeliminować dane wyjściowe terminala lub zapisy plików jako wąskie gardło wydajności.
Skonfigurujmy dysk RAM, aby wyeliminować We / Wy dysku jako potencjalne wąskie gardło. Ja osobiście mam tmpfs
zamontowany w, /tmp
więc po prostu umieściłem go testfile
w tym eksperymencie.
Następnie raz tworzę losowy plik testowy zawierający określoną liczbę linii $numoflines
o losowej długości linii i losowych danych za pomocą tego polecenia (zauważ, że zdecydowanie nie jest optymalny, staje się naprawdę wolny dla około> 2M linii, ale kogo to obchodzi, to nie jest rzecz, którą analizujemy):
cat /dev/urandom | base64 -w0 | tr 'n' '\n'| head -n "$numoflines" > testfile
Och, przy okazji. mój testowy laptop działa pod kontrolą Ubuntu 16.04, 64-bit na procesorze Intel i5-6200U. Dla porównania.
Czas dużych plików:
Konfigurowanie ogromnej testfile
:
Uruchomienie powyższej komendy z numoflines=10000000
wygenerowanym losowym plikiem zawierającym 10 mln linii, zajmującym nieco ponad 600 MB - jest dość duże, ale zacznijmy od niego, ponieważ możemy:
$ wc -l testfile
10000000 testfile
$ du -h testfile
611M testfile
$ head -n 3 testfile
qOWrzWppWJxx0e59o2uuvkrfjQbzos8Z0RWcCQPMGFPueRKqoy1mpgjHcSgtsRXLrZ8S4CU8w6O6pxkKa3JbJD7QNyiHb4o95TSKkdTBYs8uUOCRKPu6BbvG
NklpTCRzUgZK
O/lcQwmJXl1CGr5vQAbpM7TRNkx6XusYrO
Wykonaj bieg na czas z naszym ogromnym testfile
:
Teraz zróbmy tylko jeden czas z obu komend, aby oszacować, z jaką wielkością pracujemy.
$ 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
Widzimy już naprawdę wyraźny wynik dla dużych plików, tail
jest o wiele szybszy niż sed
. Ale dla zabawy i dla pewności, że nie ma przypadkowych efektów ubocznych, które mogą mieć duże znaczenie, zróbmy to 100 razy:
$ 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
Wniosek pozostaje ten sam, sed
jest nieefektywny, aby usunąć pierwszą linię dużego pliku, tail
należy tam użyć.
I tak, wiem, że konstrukcje pętli Basha są powolne, ale robimy tutaj tylko kilka iteracji, a czas potrzebny na zwykłą pętlę nie jest znaczący w porównaniu z sed
/ tail
runtimes.
Czas małe pliki:
Konfigurowanie małego testfile
:
Teraz dla kompletności, spójrzmy na bardziej powszechny przypadek, w którym masz mały plik wejściowy w zakresie kB. Utwórzmy losowy plik wejściowy numoflines=100
, wyglądający tak:
$ wc -l testfile
100 testfile
$ du -h testfile
8,0K testfile
$ head -n 3 testfile
tYMWxhi7GqV0DjWd
pemd0y3NgfBK4G4ho/
aItY/8crld2tZvsU5ly
Wykonaj bieg na czas za pomocą naszego małego testfile
:
Ponieważ możemy oczekiwać, że czasy tak małych plików mieszczą się w zakresie kilku milisekund od doświadczenia, zróbmy od razu 1000 iteracji:
$ 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
Jak widać, czasy są dość podobne, nie ma wiele do interpretacji ani zastanowienia. W przypadku małych plików oba narzędzia są równie dobrze dostosowane.
sed
jest bardziej przenośna: „+2” dlatail
działa dobrze na Ubuntu, który używa GNUtail
, ale nie działa na BSDtail
.