TL; DR - NÚMERO 21118
La larga historia
Josh Rosenberg descubrió que la str.translate()
función es muy lenta en comparación con el bytes.translate
, planteó un problema , afirmando que:
En Python 3, str.translate()
suele ser una pesimización del rendimiento, no una optimización.
¿Por qué fue str.translate()
lento?
La principal razón para str.translate()
ser muy lento era que la búsqueda solía realizarse en un diccionario de Python.
El uso de maketrans
empeoró este problema. El enfoque similar que utiliza bytes
crea una matriz C de 256 elementos para una búsqueda rápida en la tabla. Por lo tanto, el uso de Python de nivel superior dict
hace que str.translate()
en Python 3.4 sea muy lento.
¿Que ha pasado ahora?
El primer enfoque fue agregar un pequeño parche, translate_writer . Sin embargo, el aumento de velocidad no fue tan agradable. Pronto se probó otro parche fast_translate y arrojó muy buenos resultados de hasta un 55% de aceleración.
El cambio principal, como se puede ver en el archivo, es que la búsqueda del diccionario de Python se cambia a una búsqueda de nivel C.
Las velocidades ahora son casi las mismas que bytes
unpatched patched
str.translate 4.55125927699919 0.7898181750006188
str.translate from bytes trans 1.8910855210015143 0.779950579000797
Una pequeña nota aquí es que la mejora del rendimiento solo es prominente en las cadenas ASCII.
Como menciona JFSebastian en un comentario a continuación, antes de 3.5, la traducción solía funcionar de la misma manera tanto para casos ASCII como no ASCII. Sin embargo, a partir de 3.5 ASCII el caso es mucho más rápido.
Anteriormente, ASCII frente a no ascii solía ser casi lo mismo, sin embargo, ahora podemos ver un gran cambio en el rendimiento.
Puede ser una mejora de 71,6 μs a 2,33 μs como se ve en esta respuesta .
El siguiente código demuestra esto
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
Tabulación de los resultados:
Python 3.4 Python 3.5
Ascii 91.2 2.3
Unicode 101 117
dict.fromkeys(ord(c) for c in '@#$')
:?