Perché il WC è così lento?


17

Perché l'utilità wc è così lenta?

Quando lo eseguo su un file di grandi dimensioni, ci vuole circa 20 volte più a lungo di md5sum:

MyDesktop:/tmp$ dd if=/dev/zero bs=1024k count=1024 of=/tmp/bigfile
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.687094 s, 1.6 GB/s

MyDesktop:/tmp$ time wc /tmp/bigfile 
         0          0 1073741824 /tmp/bigfile

real    0m45.969s
user    0m45.424s
sys     0m0.424s

MyDesktop:/tmp$ time md5sum /tmp/bigfile 
cd573cfaace07e7949bc0c46028904ff  /tmp/bigfile

real    0m2.520s
user    0m2.196s
sys     0m0.316s

Non è solo una strana condizione limite perché il file è pieno di valori nulli, vedo la stessa differenza nelle prestazioni anche se il file è pieno di dati casuali o è un file di testo.

(questo è su Ubuntu 13.04, 64 bit)


Nota per coloro a cui interessa solo il conteggio delle righe: wc -l <nomefile> è molto più veloce su file molto grandi.
EL

Risposte:


27

Quindi sono andato alla fonte e sembra che la lentezza sia nella gestione dei caratteri a doppio byte. In sostanza, per ogni personaggio letto, deve chiamare mbrtowc()per provare a convertirlo in un carattere largo, quindi quel carattere largo viene testato per vedere se è un separatore di parole, un separatore di linea, ecc.

In effetti, se cambio la mia LANGvariabile locale da quella predefinita en_US.UTF-8(UTF-8 è un set di caratteri multibyte) e la imposto su " C" (semplice set di caratteri a byte singolo), wcè in grado di utilizzare le ottimizzazioni a byte singolo, che accelera notevolmente, impiegando solo un quarto di tempo rispetto a prima.

Inoltre, deve controllare ogni carattere solo se sta contando word ( -w), line length ( -L) o character ( -m). Se sta eseguendo solo conteggi di byte e / o righe, può saltare l'ampia gestione dei caratteri e quindi funziona in modo estremamente rapido, più veloce di md5sum.

Ho eseguito attraverso gprof, e le funzioni che vengono utilizzati per gestire i caratteri multibyte ( mymbsinit(), mymbrtowc(), myiswprint(), ecc) che occupano circa il 30% del tempo di esecuzione da solo, e il codice che passi attraverso il buffer è molto più complessa perché deve gestire passaggi di dimensioni variabili attraverso il buffer per caratteri di dimensioni variabili, nonché riempire eventuali caratteri parzialmente completati che coprono il buffer all'inizio del buffer in modo che possa essere gestito la volta successiva.

Ora che so cosa cercare, ho trovato alcuni post che menzionano la lentezza utf-8 con alcune utilità:

/programming/13913014/grepping-a-huge-file-80gb-any-way-to-speed-it-up http://dtrace.org/blogs/brendan/2011/12/08 / 2000x-prestazioni-win /


2
Oh, ho appena capito che sei OP. : p
Ivan Chau,

2
Sebbene questa sia la risposta più votata, è irrilevante. md5sumnon ti permetterà mai di contare il numero di parole e wcnon calcolerà l'hash md5 del file! È come chiedere perché la mia macchina è così lenta rispetto alla mia macchina da scrivere quando scrivo un testo.
user49468,

5
@ user49468: è ragionevole supporre che entrambi siano associati a IO, poiché entrambi devono leggere ogni singolo byte del file di input. Questa risposta dimostra che wcin realtà è associato alla CPU, durante l'elaborazione di caratteri multi-byte.
Salterio,

2
@ user49468: wc e md5sum possono fare cose diverse, ma entrambi leggono un file e fanno un calcolo relativamente semplice, si calcola una somma di controllo, si contano byte, separatori di parole e righe. Bene, ho pensato che fosse semplice, ma non avevo considerato l'ulteriore complessità dei set di caratteri multibyte. È più come chiedere "Perché la mia auto è 20 volte più veloce ad andare al negozio rispetto al mio minivan?" Ti aspetteresti qualche differenza tra i due, ma non una differenza di 20X.
Johnny,

1
@Johnny il tuo confronto auto / minivan non ha l'aspetto che entrambi sono progettati per trasportarti al negozio. Quindi un confronto di velocità è a posto. Il confronto della tua auto con il veicolo di verniciatura a strisce è più adatto. Solo perché entrambi usano le strade la loro velocità non è rilevante in quanto il pittore delle strisce non è adatto per fare shopping e viceversa.
user49468,

1

Solo un'ipotesi ma stai paragonando le mele alle arance rispetto a ciò che wcsta facendo rispetto a ciò che md5sumsta facendo.

Compito di md5sum

Quando md5sumelabora un file, apre semplicemente il file come flusso e quindi avvia l'esecuzione del flusso attraverso la funzione checksum MD5 che richiede pochissima memoria. Essenzialmente associato a I / O della CPU e del disco.

compito di wc

Quando wcviene eseguito, sta facendo molto di più, quindi analizza il file un personaggio alla volta. Deve effettivamente analizzare la struttura del file, le linee alla volta, determinando dove si trovano i confini tra i caratteri e se si tratta di un limite di parole o meno.

Esempio

Pensa alle seguenti stringhe e al modo in cui ciascuno degli algoritmi dovrebbe spostarsi mentre le analizza:

“Hello! Greg”
“Hello!Greg”
“Hello\nGreg”
“A.D.D.”
“Wow, how great!”
“wow     \n\n\n    great”
“it was a man-eating shark.”

Per MD5, si muove banalmente attraverso queste stringhe un personaggio alla volta. Perché wcdeve decidere cosa è un limite di parole e linee e tenere traccia del numero di occorrenze che vede.

Discussioni aggiuntive sul wc

Ho trovato questa sfida di codifica del 2006 che parla dell'implementazione wcin .NET. Le difficoltà sono piuttosto evidenti se si guarda ad alcuni degli pseudo codici, quindi questo potrebbe aiutare a iniziare a fare luce sul perché wcsembra essere molto più lento di altre operazioni.


1
Stai descrivendo qualcosa di diverso rispetto al comando standard Unix wc (almeno, non quello fornito con Ubuntu). Quel wc non conta parole uniche , solo parole, quindi "ciao ciao mondo" è 3 parole, non 2.
Johnny,

Sulla base di questa teoria sembra che un compito più semplice, come contare le linee, andrebbe più rapidamente. La modifica di "wc" per specificare un conteggio di riga modifica sostanzialmente i risultati? 'wc -l'
Joshua Miller,

@Johnny - Non ho mai detto che conta parole uniche che hai detto. wcconta più cose mentre analizza il file. Conta il numero di parole, linee e byte mentre analizza il file. Leggi la pagina man!
slm

@JoshuaMiller - Non è chiaro se dire wcche contare solo le linee limita il suo parsing interno in modo che conti solo queste cose o riporti solo i risultati delle linee, anche se ha comunque contato tutto.
slm

@slm Hai detto che conta parole uniche, il tuo esempio dice “Ciao! Greg "risulta in Hello 1, Greg 1 , ovvero conta per ogni parola. E il progetto .Net a cui hai collegato dice "Uno dei suoi compiti principali è quello di passare attraverso una serie di dati e contare il numero di ripetizioni di una determinata parola. Ad esempio, data la frase" Ciao, sì, ciao "ti direbbe che la parola Hello è stata usata due volte e la parola yes è stata usata una volta. " Mentre in realtà il risultato dell'eco "Ciao, sì ciao" | wc --words , è "3", non "Ciao: 2, Sì: 1"
Johnny,
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.