TL; DR - NUMÉRO 21118
La longue histoire
Josh Rosenberg a découvert que la str.translate()
fonction est très lente par rapport au bytes.translate
, il a soulevé un problème , déclarant que:
En Python 3, il str.translate()
s'agit généralement d'une pessimisation des performances, pas d'une optimisation.
Pourquoi était str.translate()
lent?
La principale raison str.translate()
d'être très lente était que la recherche se faisait auparavant dans un dictionnaire Python.
L'utilisation de maketrans
a aggravé ce problème. L'approche similaire utilisant bytes
crée un tableau C de 256 éléments pour une recherche rapide dans la table. Par conséquent, l'utilisation de Python de niveau supérieur dict
rend le str.translate()
Python 3.4 très lent.
Que s'est-il passé maintenant?
La première approche consistait à ajouter un petit patch, translate_writer , mais l'augmentation de la vitesse n'était pas si agréable. Bientôt un autre patch fast_translate a été testé et il a donné de très bons résultats allant jusqu'à 55% d'accélération.
Le principal changement, comme on peut le voir dans le fichier, est que la recherche du dictionnaire Python est transformée en une recherche de niveau C.
Les vitesses sont maintenant presque les mêmes que bytes
unpatched patched
str.translate 4.55125927699919 0.7898181750006188
str.translate from bytes trans 1.8910855210015143 0.779950579000797
Une petite remarque ici est que l'amélioration des performances n'est importante que dans les chaînes ASCII.
Comme le mentionne JFSebastian dans un commentaire ci-dessous, Avant 3.5, translate fonctionnait de la même manière pour les cas ASCII et non ASCII. Cependant, à partir de 3,5, le cas ASCII est beaucoup plus rapide.
Auparavant, ASCII et non-ascii étaient presque les mêmes, mais nous pouvons maintenant voir un grand changement dans les performances.
Cela peut être une amélioration de 71,6 μs à 2,33 μs, comme le montre cette réponse .
Le code suivant illustre cela
python3.5 -m timeit -s "text = 'mJssissippi'*100; d=dict(J='i')" "text.translate(d)"
100000 loops, best of 3: 2.3 usec per loop
python3.5 -m timeit -s "text = 'm\U0001F602ssissippi'*100; d={'\U0001F602': 'i'}" "text.translate(d)"
10000 loops, best of 3: 117 usec per loop
python3 -m timeit -s "text = 'm\U0001F602ssissippi'*100; d={'\U0001F602': 'i'}" "text.translate(d)"
10000 loops, best of 3: 91.2 usec per loop
python3 -m timeit -s "text = 'mJssissippi'*100; d=dict(J='i')" "text.translate(d)"
10000 loops, best of 3: 101 usec per loop
Tabulation des résultats:
Python 3.4 Python 3.5
Ascii 91.2 2.3
Unicode 101 117
dict.fromkeys(ord(c) for c in '@#$')
?