Prestazioni di sed
vs. tail
per rimuovere la prima riga di un file
TL; DR
sed
è molto potente e versatile, ma questo è ciò che lo rende lento, specialmente per file di grandi dimensioni con molte linee.
tail
fa solo una cosa semplice, ma quella lo fa bene e velocemente, anche per file più grandi con molte linee.
Per file di piccole e medie dimensioni sed
e tail
prestazioni altrettanto veloci (o lente, a seconda delle aspettative). Tuttavia, per file di input più grandi (più MB), la differenza di prestazioni aumenta in modo significativo (un ordine di grandezza per i file nell'intervallo di centinaia di MB), con tail
prestazioni nettamente superiori sed
.
Sperimentare
Preparazioni generali:
I nostri comandi da analizzare sono:
sed '1d' testfile > /dev/null
tail -n +2 testfile > /dev/null
Si noti che sto eseguendo il piping dell'output /dev/null
ogni volta per eliminare l'output del terminale o le scritture di file come collo di bottiglia delle prestazioni.
Configuriamo un disco RAM per eliminare l'I / O del disco come potenziale collo di bottiglia. Personalmente ne ho tmpfs
montato uno , /tmp
quindi ho semplicemente messo il mio testfile
lì per questo esperimento.
Quindi una volta sto creando un file di test casuale contenente una determinata quantità di linee $numoflines
con lunghezza di linea casuale e dati casuali usando questo comando (nota che non è assolutamente ottimale, diventa molto lento per circa> 2 M di linee, ma a chi importa, non è il cosa che stiamo analizzando):
cat /dev/urandom | base64 -w0 | tr 'n' '\n'| head -n "$numoflines" > testfile
Oh, a proposito. il mio portatile di prova esegue Ubuntu 16.04, 64 bit su una CPU Intel i5-6200U. Solo per confronto.
Timing di file di grandi dimensioni:
Impostare un enorme testfile
:
L'esecuzione del comando sopra ha numoflines=10000000
prodotto un file casuale contenente 10 milioni di righe, che occupa un po 'più di 600 MB - è piuttosto enorme, ma iniziamo con esso, perché possiamo:
$ wc -l testfile
10000000 testfile
$ du -h testfile
611M testfile
$ head -n 3 testfile
qOWrzWppWJxx0e59o2uuvkrfjQbzos8Z0RWcCQPMGFPueRKqoy1mpgjHcSgtsRXLrZ8S4CU8w6O6pxkKa3JbJD7QNyiHb4o95TSKkdTBYs8uUOCRKPu6BbvG
NklpTCRzUgZK
O/lcQwmJXl1CGr5vQAbpM7TRNkx6XusYrO
Esegui la corsa a tempo con il nostro enorme testfile
:
Ora facciamo solo una singola corsa cronometrata con entrambi i comandi per stimare prima con quale grandezza stiamo lavorando.
$ 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
Vediamo già un risultato davvero chiaro per i file di grandi dimensioni, tail
è di una grandezza più veloce di sed
. Ma solo per divertimento e per essere sicuri che non ci siano effetti collaterali casuali che fanno una grande differenza, facciamolo 100 volte:
$ 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
La conclusione rimane la stessa, sed
è inefficiente per rimuovere la prima riga di un file di grandi dimensioni, tail
dovrebbe essere utilizzata lì.
E sì, so che i costrutti del ciclo di Bash sono lenti, ma stiamo facendo solo relativamente poche iterazioni qui e il tempo impiegato da un ciclo normale non è significativo rispetto ai sed
/ tail
runtime comunque.
Timing di file di piccole dimensioni:
Impostare un piccolo testfile
:
Ora per completezza, diamo un'occhiata al caso più comune che hai un piccolo file di input nell'intervallo kB. Creiamo un file di input casuale con numoflines=100
, simile al seguente:
$ wc -l testfile
100 testfile
$ du -h testfile
8,0K testfile
$ head -n 3 testfile
tYMWxhi7GqV0DjWd
pemd0y3NgfBK4G4ho/
aItY/8crld2tZvsU5ly
Esegui la corsa a tempo con il nostro piccolo testfile
:
Poiché possiamo aspettarci che i tempi per file così piccoli siano nel giro di pochi millisecondi per esperienza, facciamo subito 1000 iterazioni:
$ 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
Come puoi vedere, i tempi sono abbastanza simili, non c'è molto da interpretare o meravigliarsi. Per file di piccole dimensioni, entrambi gli strumenti sono ugualmente adatti.
sed
è più portabile: "+2"tail
funziona bene su Ubuntu, che usa GNUtail
, ma non funziona su BSDtail
.