Leistung von sed
vs. tail
, um die erste Zeile einer Datei zu entfernen
TL; DR
sed
ist sehr leistungsfähig und vielseitig, aber das macht es langsam, besonders für große Dateien mit vielen Zeilen.
tail
macht nur eine einfache Sache, aber diese macht es gut und schnell, auch für größere Dateien mit vielen Zeilen.
Für kleine und mittlere Dateien sed
und tail
mit ähnlich hoher Geschwindigkeit (oder geringer Geschwindigkeit, je nach Ihren Erwartungen). Bei größeren Eingabedateien (mehrere MB) nimmt der Leistungsunterschied jedoch erheblich zu (eine Größenordnung für Dateien im Bereich von Hunderten von MB), wobei eine tail
deutliche Outperformance erzielt wird sed
.
Experiment
Allgemeine Vorbereitungen:
Unsere zu analysierenden Befehle sind:
sed '1d' testfile > /dev/null
tail -n +2 testfile > /dev/null
Beachten Sie, dass ich die Ausgabe /dev/null
jedes Mal weiterleite, um die Terminalausgabe oder die Dateischreibvorgänge als Leistungsengpass zu beseitigen.
Richten wir eine RAM-Disk ein, um die Festplatten-E / A als potenziellen Engpass zu beseitigen. Ich persönlich habe ein tmpfs
Reittier bei, /tmp
also habe ich es einfach testfile
für dieses Experiment hingestellt.
Dann erstelle ich $numoflines
mit diesem Befehl einmal eine zufällige Testdatei mit einer festgelegten Anzahl von Zeilen mit zufälliger Zeilenlänge und zufälligen Daten (beachten Sie, dass dies definitiv nicht optimal ist, da es für über 2 Millionen Zeilen sehr langsam wird, aber wen interessiert das, es ist nicht das was wir analysieren):
cat /dev/urandom | base64 -w0 | tr 'n' '\n'| head -n "$numoflines" > testfile
Oh, übrigens. Auf meinem Test-Laptop läuft Ubuntu 16.04, 64-Bit auf einer Intel i5-6200U-CPU. Nur zum Vergleich.
Timing großer Dateien:
Riesen aufbauen testfile
:
Wenn Sie den obigen Befehl mit numoflines=10000000
einer zufälligen Datei ausführen, die 10 Millionen Zeilen enthält und etwas mehr als 600 MB belegt - das ist ziemlich umfangreich, aber fangen wir damit an, denn wir können:
$ wc -l testfile
10000000 testfile
$ du -h testfile
611M testfile
$ head -n 3 testfile
qOWrzWppWJxx0e59o2uuvkrfjQbzos8Z0RWcCQPMGFPueRKqoy1mpgjHcSgtsRXLrZ8S4CU8w6O6pxkKa3JbJD7QNyiHb4o95TSKkdTBYs8uUOCRKPu6BbvG
NklpTCRzUgZK
O/lcQwmJXl1CGr5vQAbpM7TRNkx6XusYrO
Führen Sie den zeitgesteuerten Lauf mit unserem riesigen testfile
:
Lassen Sie uns nun zunächst mit beiden Befehlen einen einzigen zeitgesteuerten Lauf durchführen, um abzuschätzen, mit welchen Größen wir arbeiten.
$ 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
Wir sehen bereits ein wirklich eindeutiges Ergebnis für große Dateien, das tail
um eine Größenordnung schneller ist als sed
. Aber nur zum Spaß und um sicherzugehen, dass es keine zufälligen Nebenwirkungen gibt, die einen großen Unterschied machen, machen wir es 100 Mal:
$ 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
Die Schlussfolgerung bleibt gleich, sed
ist ineffizient, um die erste Zeile einer großen Datei zu entfernen, tail
sollte dort verwendet werden.
Und ja, ich weiß, dass die Loop-Konstrukte von Bash langsam sind, aber wir machen hier nur relativ wenige Iterationen, und die Zeit, die eine einfache Loop benötigt, ist im Vergleich zu den sed
/ tail
-Laufzeiten sowieso nicht signifikant .
Timing kleiner Dateien:
Ein kleines einrichten testfile
:
Betrachten wir der Vollständigkeit halber den häufigeren Fall, dass Sie eine kleine Eingabedatei im kB-Bereich haben. Lass uns eine zufällige Eingabedatei erstellen numoflines=100
, die so aussieht:
$ wc -l testfile
100 testfile
$ du -h testfile
8,0K testfile
$ head -n 3 testfile
tYMWxhi7GqV0DjWd
pemd0y3NgfBK4G4ho/
aItY/8crld2tZvsU5ly
Führen Sie den zeitgesteuerten Lauf mit unserem kleinen testfile
:
Da wir aus Erfahrung damit rechnen können, dass das Timing für solche kleinen Dateien im Bereich einiger Millisekunden liegt, lassen Sie uns gleich 1000 Iterationen durchführen:
$ 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
Wie Sie sehen, sind die Timings ziemlich ähnlich, es gibt nicht viel zu interpretieren oder sich darüber zu wundern. Für kleine Dateien sind beide Tools gleich gut geeignet.
sed
es portabler ist: "+2" fürtail
funktioniert gut unter Ubuntu, das GNU verwendettail
, aber unter BSD nicht funktionierttail
.