In che modo ksh93 è così veloce?


9

Quindi, in generale, tendo a cercare l' sedelaborazione del testo - specialmente per file di grandi dimensioni - e di solito evito di fare quel genere di cose nella shell stessa.

Penso, tuttavia, che potrebbe cambiare. Stavo frugando in giro man kshe ho notato questo:

<#pattern     Seeks forward to the beginning of the
              next line containing pattern.

<##pattern    The same as <# except that  the  por
              tion  of  the file that is skipped is
              copied to standard output.

Scettico sull'utilità del mondo reale, ho deciso di provarlo. L'ho fatto:

seq -s'foo bar
' 1000000 >file

... per un milione di righe di dati che sembrano:

1foo bar
...
999999foo bar
1000000

... e lo ha confrontato sedcome:

p='^[^0-8]99999.*bar'
for c in "sed '/$p/q'" "ksh -c ':<##@(~(E)$p)'"    
do </tmp/file eval "time ( $c )"
done | wc -l

Quindi entrambi i comandi dovrebbero arrivare fino a 999999foo bar e la loro implementazione della corrispondenza del modello deve valutare almeno l'inizio e la fine di ogni riga per poterlo fare. Devono anche verificare il primo carattere rispetto a un modello negato. Questa è una cosa semplice, ma ... I risultati non erano quelli che mi aspettavo:

( sed '/^[^0-8]99999.*bar/q' ) \
    0.40s user 0.01s system 99% cpu 0.419 total
( ksh -c ':<##@(~(E)^[^0-8]99999.*bar)' ) \
    0.02s user 0.01s system 91% cpu 0.033 total
1999997

kshusa ERE qui e sedun BRE. Ho fatto la stessa cosa con kshe un modello di shell prima, ma i risultati non differivano.

Comunque, questa è una discrepanza abbastanza significativa - kshsupera sed10 volte. Ho già letto che David Korn ha scritto il suo io lib e lo implementa ksh- forse questo è legato? - ma non so quasi nulla al riguardo. Come mai la shell lo fa così bene?

Ancora più sorprendente per me è che kshlascia davvero il suo offset proprio dove lo chiedi. Per ottenere (quasi) lo stesso da (GNU) sed devi usare -u- molto lentamente .

Ecco un grepv. kshTest:

1000000         #grep + head
( grep -qm1 '^[^0-8]99999.*bar'; head -n1; ) \
    0.02s user 0.00s system 90% cpu 0.026 total
999999foo bar   #ksh + head
( ksh -c ':<#@(~(E)^[^0-8]99999.*bar)'; head -n1; )  \
    0.02s user 0.00s system 73% cpu 0.023 total

kshi battiti grepqui - ma non sempre - sono praticamente legati. Tuttavia, è piuttosto eccellente e ksh fornisce un headinput lookhead prima dell'inizio della partita.

Sembra troppo bello per essere vero, immagino. Cosa stanno facendo questi comandi in modo diverso sotto il cofano?

Oh, e apparentemente non c'è nemmeno una subshell qui:

ksh -c 'printf %.5s "${<file;}"'

È patternun'espressione regolare o un modello di shell più semplice?
muru,

@muru - Può anche essere, ma non sono molto bravo a cambiarli. Nell'esempio è un modello di shell: il valore predefinito.
Mikeserv,

@muru - Ne ho aggiunto uno con regex.
Mikeserv,

Risposte:


8

Non solo ksh usa sfio ma usa un proprio allocatore di memoria personalizzato.

Tuttavia, la mia ipotesi è che lo sfio faccia la differenza in questo caso. Ho appena provato a eseguire il tuo esempio sotto strace e posso vedere che ksh chiama read / write ~ 200 volte (blocchi da 65 KB) mentre sed lo fa ~ 3400 volte (blocchi da 4 KB). Con sed -u il mio laptop è quasi sciolto, le letture vengono eseguite per byte e le scritture per riga. Ksh usa semplicemente lseek. Grep usa la lettura ~ 400 volte (blocchi da 32 KB).


Sì, senza buffer non è per i deboli di cuore. Mi chiedo se kshil motore regex sia efficiente come il suo io? Comunque, grazie mille per la risposta. Mi scuso con il tuo laptop. Che dire dell'allocatore di memoria personalizzato, però? Ne hai ancora?
mikeserv,

1
Purtroppo no. Ovviamente puoi scaricare il codice sorgente dal sito web di t, ma questo è tutto. La libreria si chiama AST e contiene allocatore, motore regex e molte altre cose. Quindi è del tutto possibile che la combinazione di tutte queste cose renda ksh molto più veloce.
Miroslav Franc,


Grazie - anche questo sembra promettente: alcuni dei componenti disponibili nella raccolta di software AST sono: Comandi POSIX La maggior parte dei comandi POSIX standard sono disponibili nella raccolta AST. Molti sono codificati come funzioni di libreria che possono essere aggiunte a ksh come comando integrato che migliora notevolmente le prestazioni. - Ora devo solo capire come costruirlo,
mikeserv il

1
@mikeserv ksh può essere creato per utilizzare l' allocatore vmalloc di Phong Vo . Articoli di giornale disponibili a quel link.
Mark Plotnick,
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.