J'essayais de supprimer les caractères indésirables d'une chaîne donnée en utilisant text.translate()
Python 3.4.
Le code minimal est:
import sys
s = 'abcde12345@#@$#%$'
mapper = dict.fromkeys(i for i in range(sys.maxunicode) if chr(i) in '@#$')
print(s.translate(mapper))
Cela fonctionne comme prévu. Cependant, le même programme lorsqu'il est exécuté en Python 3.4 et Python 3.5 donne une grande différence.
Le code pour calculer les horaires est
python3 -m timeit -s "import sys;s = 'abcde12345@#@$#%$'*1000 ; mapper = dict.fromkeys(i for i in range(sys.maxunicode) if chr(i) in '@#$'); " "s.translate(mapper)"
Le programme Python 3.4 prend 1,3 ms alors que le même programme en Python 3.5 ne prend que 26,4 μs .
Qu'est-ce qui s'est amélioré dans Python 3.5 qui le rend plus rapide par rapport à Python 3.4?
python
string
python-3.x
python-internals
python-3.5
Bhargav Rao
la source
la source
dict.fromkeys(ord(c) for c in '@#$')
?Réponses:
TL; DR - NUMÉRO 21118
La longue histoire
Josh Rosenberg a découvert que la
str.translate()
fonction est très lente par rapport aubytes.translate
, il a soulevé un problème , déclarant que: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 utilisantbytes
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érieurdict
rend lestr.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
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
Tabulation des résultats:
la source
55
%: comme le montre votre réponse, l'accélération peut être de1000
s% .python3.5 -m timeit -s "text = 'mJssissippi'*100; d=dict(J='i')" "text.translate(d)"
(ascii) vspython3.5 -m timeit -s "text = 'm\U0001F602ssissippi'*100; d={'\U0001F602': 'i'}" "text.translate(d)"
(non-ascii). Ce dernier est beaucoup (10x) plus lent..translate()
c'est-à-dire que le cas ascii est beaucoup plus rapide en Python 3.5 uniquement (vous n'avez pas besoinbytes.translate()
de performances là-bas).