Wie ist ksh93 so schnell?

9

Daher tendiere ich im Allgemeinen dazu, nach sedTextverarbeitung zu suchen - insbesondere nach großen Dateien - und vermeide es normalerweise, solche Dinge in der Shell selbst zu tun.

Ich denke jedoch, dass sich das ändern kann. Ich stöberte herum man kshund bemerkte Folgendes:

<#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.

Ich war skeptisch gegenüber der Nützlichkeit der realen Welt und beschloss, es auszuprobieren. Ich tat:

seq -s'foo bar
' 1000000 >file

... für eine Million Datenzeilen, die aussehen wie:

1foo bar
...
999999foo bar
1000000

... und stellte es gegen sedwie:

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

Daher sollten beide Befehle bis zu 999999foo bar erhalten, und ihre Implementierung für den Mustervergleich muss mindestens den Anfang und das Ende jeder Zeile auswerten, um dies zu tun. Sie müssen auch das erste Zeichen anhand eines negierten Musters überprüfen. Dies ist eine einfache Sache, aber ... Die Ergebnisse waren nicht das, was ich erwartet hatte:

( 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

kshverwendet hier ERE und sedein BRE. Ich habe das gleiche mit kshund einem Shell-Muster gemacht, aber die Ergebnisse unterschieden sich nicht.

Wie auch immer, das ist eine ziemlich bedeutende Diskrepanz - kshübertrifft das sedZehnfache. Ich habe vorher gelesen, dass David Korn seine eigene io lib geschrieben und implementiert hat ksh- möglicherweise hängt das damit zusammen? - aber ich weiß so gut wie nichts darüber. Wie kommt es, dass die Shell das so gut macht?

Noch erstaunlicher für mich ist, dass kshder Versatz wirklich genau dort bleibt, wo Sie ihn fragen. Um (fast) dasselbe aus (GNU) herauszuholen sed, muss man verwenden -u- sehr langsam .

Hier ist ein 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

kshBeats grephier - aber nicht immer - sie sind ziemlich gebunden. Trotzdem ist das ziemlich gut und ksh bietet Lookahead - headdie Eingabe beginnt vor dem Match.

Es scheint einfach zu schön, um wahr zu sein, denke ich. Was machen diese Befehle unter der Haube anders?

Oh, und anscheinend gibt es hier nicht einmal eine Unterschale:

ksh -c 'printf %.5s "${<file;}"'
mikeserv
quelle
Ist das patternein regulärer Ausdruck oder ein einfacheres Shell-Muster?
Muru
@muru - Es kann auch sein, aber ich bin nicht sehr gut darin, diese zu ändern. Im Beispiel ist es ein Shell-Muster - die Standardeinstellung.
Mikeserv
@muru - Ich habe einen mit einem regulären Ausdruck hinzugefügt.
Mikeserv

Antworten:

8

Ksh verwendet nicht nur sfio, sondern auch einen eigenen benutzerdefinierten Speicherzuweiser.

Trotzdem denke ich, dass sfio in diesem Fall den Unterschied macht. Ich habe gerade versucht, Ihr Beispiel unter Strace auszuführen, und kann sehen, dass ksh-Aufrufe ~ 200-mal (65-KB-Blöcke) lesen / schreiben, während sed ~ 3400-mal (4-KB-Blöcke) ausführt. Mit sed -u ist mein Laptop fast geschmolzen, Lesevorgänge erfolgen pro Byte und Schreibvorgänge pro Zeile. Ksh simple verwendet lseek. Grep verwendet ~ 400-mal Lesen (32-KB-Blöcke).

Miroslav Franc
quelle
Ja - ungepuffert ist nichts für schwache Nerven. Ich frage mich, ob kshdie Regex-Engine als Io effizient ist. Trotzdem vielen Dank für die Antwort. Ich entschuldige mich bei Ihrem Laptop. Was ist jedoch mit dem benutzerdefinierten Speicherzuweiser? Hast du noch mehr dazu?
Mikeserv
1
Traurigerweise Nein. Sie können den Quellcode natürlich von der & t-Website herunterladen, aber das war's auch schon. Die Bibliothek heißt AST und enthält Allokator, Regex-Engine und viele andere Dinge. Es ist also durchaus möglich, dass die Kombination all dieser Dinge ksh viel schneller macht.
Miroslav Franc
Vielen Dank - auch das sieht vielversprechend aus: Einige der in der AST-Software-Sammlung verfügbaren Komponenten sind: POSIX-Befehle Die meisten Standard-POSIX-Befehle sind in der AST-Sammlung verfügbar. Viele sind als Bibliotheksfunktionen codiert, die als integrierter Befehl zu ksh hinzugefügt werden können, wodurch die Leistung erheblich verbessert wird. - Jetzt muss ich nur noch herausfinden, wie man es baut
Mikeserv
1
@mikeserv ksh kann für die Verwendung des vmalloc - Allokators von Phong Vo erstellt werden . Zeitschriftenartikel unter diesem Link verfügbar.
Mark Plotnick