Lo strumento `uniq` più veloce in linux


8

Ho un file di testo di grandi dimensioni (1,5 G),

Voglio sapere qual è lo strumento più veloce e affidabile in Linux.

Di solito uso:

awk '!x[$0]++' file.txt

Ma quando uso il htopcomando vedo che l'utilizzo della mia memoria è in aumento.

Voglio sapere qual è il più veloce e affidabile per file di grandi dimensioni.

uniq?
sort?
sed?
awk?

Perché?


Hai provato a eseguirli, possibilmente con time?
Choroba,

il tempo è importante e anche l'uso della memoria e l'affidabilità (intendo quale fa esattamente il suo lavoro)
MLSC,

Non ancora ... Ma ho fatto alcuni test prima ... e chiedo da qualche parte, alcuni ragazzi mi hanno detto che Awk è il migliore ... ma in cima ... Vedo che l'utilizzo della memoria sta aumentando
MLSC,

3
@MortezaLSC: è un compromesso. Più veloce è il programma, più memoria viene utilizzata.
cuonglm,

Risposte:


16

Consideriamo come funziona ciascuna soluzione.

  • uniqCiò richiede che il file sia già ordinato. In caso contrario, è necessario reindirizzarlo sortprima, il che significa che sortè necessario leggere l'intero file in memoria, riordinarlo ( O(n log n)) e quindi scriverlo nella pipe. Il lavoro di uniqè molto economico, dal momento che deve solo confrontare le linee adiacenti del suo input.

  • sort -uQuesto combina il lavoro di sort | uniq. Questo deve raccogliere tutti gli input univoci in memoria come fa lo awkscript, ma poi perde tempo a ordinarli prima di produrre l'output. Questo è O(n log n), sebbene in questo caso nsia il numero di elementi univoci, non tutti gli input. Quindi è meglio della pipa.

  • sedNon sono sicuro del motivo per cui hai elencato questo, in quanto non riesco a pensare a un buon modo per farlo sed. Forse se prima lo ordini e installi uno sedscript, c'è un modo per confrontare le linee adiacenti. Quindi sedfarebbe semplicemente quello che uniqfa e uniqprobabilmente lo farà nel modo più efficiente possibile.

  • awkQuesto è probabilmente il migliore perché fa solo la minima quantità di lavoro necessario. Mentre legge ogni riga, esegue una ricerca hash efficiente per verificare se la riga è già in memoria e memorizza solo le righe univoche come chiavi hash e un contatore come valore. (Se la linea non era precedentemente presente, la condizione sarà vera, quindi la linea verrà stampata. Altrimenti non lo farà.) Questo utilizza O(n)tempo e O(uniq n)memoria.

Ogni metodo utilizzerà una notevole quantità di memoria, sia per ordinare gli input sia per tenere traccia degli input visti in modo da poter rimuovere i duplicati.


1
+1 La spiegazione relativa awkspiega anche perché utilizza quantità crescenti di memoria. Qualunque cosa faccia un ordinamento finirà per fare anche questo, solo 1) probabilmente lo userà tutto in una volta, 2) potrebbe usarne un po 'di più, a seconda del numero di chiavi univoche o duplicate.
Riccioli d'oro,

@Barmar scusa, ma quando ho un file di grandi dimensioni (16 G) con capacità di memoria 8G, quindi cosa succederà con la mia memoria?
MLSC,

8
@goldilocks, sortricorre a file temporanei (in modo intelligente) per evitare di riempire la memoria. Il suo utilizzo della memoria è limitato. Il confine è personalizzabile con alcune implementazioni di ordinamento. È più efficiente che consente al sistema di scambiare la memoria in modo casuale su disco (il che influisce anche sulle applicazioni sul sistema).
Stéphane Chazelas,

È vero. Quindi, se ti imbatti in un caso in cui awkla memoria si esaurisce, sortpotrebbe essere l'unica soluzione perché è stata progettata per far fronte a questo. D'altra parte, tutto quel disco che legge e scrive rallenterà, quindi probabilmente ci vorrà molto tempo per completarlo. Se hai a che fare con una così grande quantità di dati, probabilmente dovresti utilizzare un DBMS anziché i file di testo.
Barmar,

@Barmar Come hai dedotto che il tempo di riordino aumenta come O(n log n)? O semplicemente lo conosci da altrove?
Jimmij,


0

Volevo solo sottolineare che lo gnu uniqsembra terribilmente lento, anche in un elenco ordinato.

Ho appena provato a ottenere un elenco di prefissi di directory da un elenco di nomi di file ordinati:

$ pv all_files | cut -d '/' -f 1,2,3,4 | uniq > all_prefixes

36.7GiB 0:07:41 [81.4MiB/s]

$ pv all_files | cut -d '/' -f 1,2,3,4 | sort -u > all_prefixes2

36.7GiB 0:03:14 [ 193MiB/s]

$ pv all_files  | cut -d '/' -f 1,2,3,4 | awk '!x[$0]++' > all_prefixes3                                        
36.7GiB 0:02:18 [ 270MiB/s] 

sort -u sembra due volte più veloce di uniq, e questo è con l'ordinamento in lettura da stdin e la scrittura in stdout, quindi non vedo che faccia ancora parallelismi. Non ho idea del perché uniq dovrebbe essere molto più lento dell'ordinamento, dal momento che non deve ordinare l'elenco ...

L'outpuf di questo comando è molto piccolo (ci sono molti duplicati), solo 264kb e l'ordinamento termina immediatamente dopo che pv è stato fatto.

Le stesse velocità rimangono se si gira intorno all'ordine dei comandi, il mio flusso è limitato dal tempo della CPU qui, non dall'accesso al disco e dalla cache (ho solo 8 GB di RAM e il mio scambio non viene utilizzato)

Sto eseguendo questo su una macchina fedora 31 con gnu coreutils sort e uniq e gnu awk; la locale è impostata su en_US.UTF-8

AGGIORNAMENTO , dal momento che questo mi ha incuriosito un po 'ho fatto qualche altro test, cerchiamo di eliminare la parte tagliata e assicuriamoci che il file sia ben ordinato

cat all_files | cut -d '/' -f 1,2,3,4 | sort -T . > test

Questo richiede 8.4 minuti. il test ora è grande 7,9 GB

eseguiamo questi strumenti sul file invece che in una pipe, questo consentirà a questi strumenti di fare qualche ottimizzazione, come sort multi thread. e anche da un ssd più veloce.

Potresti non notare che anche l'ordinamento sta occupando molta memoria, dal momento che fa trucchi intelligenti con file temporanei in / tmp che potrebbero essere tmpfs e saranno nel tuo ram (prova a ordinare un file più grande di / tmp, corri nello spazio problemi, ecco perché ho bisogno del flag -T nel comando sopra)

$ time sort -u test > /dev/null
339.24user 3.54system 1:28.87elapsed 385%CPU (0avgtext+0avgdata 2365856maxresident)k
9555544inputs+0outputs (0major+591298minor)pagefaults 0swaps

$ time awk '!x[$0]++' test > /dev/null                                                                                                                             
51.15user 1.55system 0:52.94elapsed 99%CPU (0avgtext+0avgdata 10976maxresident)k
0inputs+0outputs (0major+1923minor)pagefaults 0swaps

$ time uniq test > /dev/null                                                                                                                                  
421.89user 2.76system 7:06.63elapsed 99%CPU (0avgtext+0avgdata 1980maxresident)k
52712inputs+0outputs (0major+79minor)pagefaults 0swaps

Quindi sembra che la tua soluzione Awk sia la più veloce di queste 3 e utilizzi effettivamente meno memoria

update2 e ora con una localizzazione più semplice

$ export LC_ALL=c
$ time sort -u test > /dev/null                                                                                                                                             1.2m ? Tue Apr 21 17:09:22 2020
119.18user 3.64system 0:38.24elapsed 321%CPU (0avgtext+0avgdata 2013472maxresident)k

$ time awk '!x[$0]++' test > /dev/null                                                                                                                                1161ms ? Tue Apr 21 17:07:31 2020
67.23user 2.50system 1:10.16elapsed 99%CPU (0avgtext+0avgdata 10480maxresident)k
7187520inputs+0outputs (0major+1912minor)pagefaults 0swaps

$ time uniq test > /dev/null                                                                                                                                               
22.05user 2.02system 0:24.24elapsed 99%CPU (0avgtext+0avgdata 1488maxresident)k
2959648inputs+0outputs (1major+72minor)pagefaults 0swaps

Questa volta uniq vince la gara ... come accennato da Stéphane Chazelas nei commenti, impostare il locale su C rende più veloce l'ordinamento e l'unicità!


Quale implementazione di sorte uniq? Quale locale?
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.