117 votes

Pourquoi str.translate est-il plus rapide dans Python 3.5 par rapport à Python 3.4?

J'ai essayé de supprimer les caractères d'une chaîne à l'aide de text.translate() en 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))

Il fonctionne comme prévu. Cependant, le même programme lors de l'exécution en Python Python 3.4 et 3.5 donne une grande différence.

Le code pour calculer les temps 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 Python 3.4 programme prend 1.3 ms alors que le même programme en Python 3.5 prend seulement 26.4 µs.

Ce qui a amélioré en Python 3.5 qui le rend plus rapide par rapport à Python 3.4?

151voto

Bhargav Rao Points 20835

TL;DR - QUESTION 21118


L'Histoire

Josh Rosenberg a découvert que l' str.translate() fonction est très lente par rapport à l' bytes.translate, il a soulevé une question, en déclarant que:

En Python 3, str.translate() est généralement un rendement pessimization, pas d'optimisation.

Pourquoi était - str.translate() - il lent?

La raison principale pour str.translate() très lent a été que la recherche dans un dictionnaire Python.

L'utilisation de l' maketrans fait de ce problème pour le pire. La même approche à l'aide de bytes construit un C tableau de 256 éléments de rapide de la table de recherche. Donc l'utilisation de plus haut niveau Python dict fait l' str.translate() en Python 3.4 très lent.

Ce qui s'est passé maintenant?

La première approche a été d'ajouter un petit patch, translate_writer, Cependant, l'augmentation de la vitesse n'était pas agréable. Bientôt un autre patch fast_translate a été testé et il a donné de très bons résultats jusqu'à 55% plus rapide.

Le principal changement que peut être vu à partir du fichier, c'est que le Python recherche dans le dictionnaire est changé en un C niveau de la recherche.

Les vitesses de maintenant sont 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 note ici, c'est que l'amélioration de la performance est seulement important dans les chaînes ASCII.

Comme J. F. Sebastian mentionne dans un commentaire ci-dessous, Avant de 3.5, traduire l'habitude de travailler de la même façon pour les deux ASCII et non-ASCII cas. Cependant, à partir de 3,5 ASCII cas est beaucoup plus rapide.

Plus tôt ASCII vs non-ascii utilisé pour être presque la même, mais maintenant, nous pouvons voir un grand changement dans la performance.

Il peut être une amélioration de 71.6 µs à 2,33 µs, comme on le voit dans cette réponse.

Le code suivant illustre cette

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

Dépouillement des résultats:

         Python 3.4    Python 3.5  
Ascii     91.2          2.3 
Unicode   101           117

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X