Je suis donc allé à la source, et il semble que la lenteur réside dans la gestion des caractères à deux octets. Essentiellement, pour chaque caractère lu, il doit appeler mbrtowc()
pour essayer de le convertir en caractère large, puis ce caractère large est testé pour voir s'il s'agit d'un séparateur de mots, d'un séparateur de lignes, etc.
En effet, si je change ma LANG
variable locale par défaut en_US.UTF-8
(UTF-8 est un jeu de caractères multi-octets) et que je la mets à " C
" (jeu de caractères simple à un octet), je peux wc
utiliser des optimisations à un octet, ce qui l'accélère considérablement, en prenant seulement environ un quart aussi longtemps qu'avant.
De plus, il n'a qu'à vérifier chaque caractère s'il compte les mots ( -w
), la longueur de ligne ( -L
) ou le caractère ( -m
). S'il ne fait que compter les octets et / ou les lignes, il peut ignorer la gestion des caractères larges, puis il s'exécute extrêmement rapidement - plus rapidement quemd5sum
.
Je l' ai couru à travers gprof
, et les fonctions qui sont utilisées pour gérer les caractères multi - octets ( mymbsinit()
, mymbrtowc()
, myiswprint()
, etc.) prenez environ 30% du temps d'exécution seul, et le code qui étapes à travers la mémoire tampon est beaucoup plus complexe parce qu'il doit gérer les étapes de taille variable dans le tampon pour les caractères de taille variable, ainsi que rembourrer tous les caractères partiellement complétés qui s'étendent sur le tampon jusqu'au début du tampon afin qu'il puisse être géré la prochaine fois.
Maintenant que je sais quoi chercher, j'ai trouvé quelques articles mentionnant la lenteur de l'utf-8 avec certains utilitaires:
/programming/13913014/grepping-a-huge-file-80gb-any-way-to-speed-it-up
http://dtrace.org/blogs/brendan/2011/12/08 / 2000x-performance-win /