Comment est ksh93 si rapide?

9

Donc, en général, j'ai tendance à rechercher le sedtraitement de texte - en particulier pour les gros fichiers - et à éviter généralement de faire ce genre de choses dans le shell lui-même.

Je pense cependant que cela pourrait changer. Je fouinais man kshet j'ai remarqué ceci:

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

Sceptique quant à son utilité dans le monde réel, j'ai décidé de l'essayer. J'ai fait:

seq -s'foo bar
' 1000000 >file

... pour un million de lignes de données qui ressemblent à:

1foo bar
...
999999foo bar
1000000

... et l'a opposé sedcomme:

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

Ainsi, les deux commandes doivent obtenir jusqu'à 999999foo bar et leur implémentation de correspondance de modèle doit évaluer au moins le début et la fin de chaque ligne pour ce faire. Ils doivent également vérifier le premier caractère par rapport à un modèle annulé. C'est une chose simple, mais ... Les résultats n'étaient pas ce à quoi je m'attendais:

( 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

kshutilise ERE ici et sedun BRE. J'ai fait la même chose avec kshun motif de coque auparavant, mais les résultats ne différaient pas.

Quoi qu'il en soit, c'est un écart assez important - kshsurpasse sed10 fois. J'ai lu auparavant que David Korn a écrit son propre io lib et l'implémente dans ksh- peut-être que cela est lié? - mais je n'en sais presque rien. Comment se fait-il que la coquille le fasse si bien?

Encore plus étonnant pour moi, c'est que kshcela laisse vraiment son décalage là où vous le demandez. Pour obtenir (presque) la même chose de (GNU), sed vous devez utiliser -u- très lentement .

Voici un test grepv ksh:

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

kshbat grepici - mais pas toujours - ils sont à peu près liés. Pourtant, c'est assez excellent, et ksh fournit une entrée anticipée - headcommence avant son match.

Cela semble trop beau pour être vrai, je suppose. Que font ces commandes différemment sous le capot?

Oh, et apparemment il n'y a même pas de sous-shell ici:

ksh -c 'printf %.5s "${<file;}"'
mikeserv
la source
Est-ce patternune expression régulière ou un modèle de coque plus simple?
muru
@muru - Cela peut être l'un ou l'autre, mais je ne suis pas très doué pour changer les choses. Dans l'exemple, c'est un modèle de coque - la valeur par défaut.
mikeserv
@muru - J'en ai ajouté un avec une expression régulière.
mikeserv

Réponses:

8

Non seulement ksh utilise sfio, mais il utilise son propre allocateur de mémoire personnalisé.

Néanmoins, je suppose que sfio fait la différence dans ce cas. J'ai juste essayé d'exécuter votre exemple sous strace et je peux voir que ksh appelle en lecture / écriture ~ 200 fois (blocs de 65 Ko) tandis que sed le fait ~ 3400 fois (blocs de 4 Ko). Avec sed -u mon ordinateur portable a presque fondu, les lectures se font par octet et les écritures par ligne. Ksh simple utilise lseek. Grep utilise lecture ~ 400 fois (blocs de 32 Ko).

Miroslav Franc
la source
Ouais - sans tampon n'est pas pour les faibles de cœur. Je me demande si kshle moteur regex est aussi efficace que son io? Quoi qu'il en soit, merci beaucoup pour la réponse. Mes excuses à votre ordinateur portable. Mais qu'en est-il de l'allocateur de mémoire personnalisé? En avez-vous d'autres à ce sujet?
mikeserv
1
Malheureusement non. Vous pouvez bien sûr télécharger le code source depuis le site Web at & t, mais c'est tout. La bibliothèque s'appelle AST et contient l'allocateur, le moteur d'expression régulière et bien d'autres choses. Il est donc tout à fait possible que la combinaison de toutes ces choses rend ksh beaucoup plus rapide.
Miroslav Franc
Merci - cela semble également prometteur: Certains des composants disponibles dans la collection de logiciels AST sont: Commandes POSIX La plupart des commandes POSIX standard sont disponibles dans la collection AST. Beaucoup sont codés comme des fonctions de bibliothèque qui peuvent être ajoutées à ksh en tant que commande intégrée qui améliore considérablement les performances. - Maintenant, je dois juste trouver comment le construire,
mikeserv
1
@mikeserv ksh peut être construit pour utiliser l' allocateur vmalloc de Phong Vo . Articles de revues disponibles sur ce lien.
Mark Plotnick