Luego de mucho luchar ya encontramos el resultado de esta impedimento que ciertos de nuestros lectores de este espacio han tenido. Si deseas compartir algo puedes compartir tu conocimiento.
Solución:
Puedes usar un intermedio bytearray
para acelerar las cosas:
>>> sum(bytearray("abcdefgh"))
804
Esto no es 17 veces más rápido que el generador: implica la creación de un intermediario bytearray
y sum
todavía tiene que iterar sobre objetos enteros de Python, pero en mi máquina acelera la suma de un número de 8 caracteres string desde 2μs hasta alrededor de 700ns. Si un tiempo en este estadio sigue siendo demasiado ineficiente para su caso de uso, probablemente debería escribir las partes críticas de velocidad de su aplicación en C de todos modos.
Si sus cadenas son lo suficientemente grandes, y si puede usar numpy
puede evitar la creación de copias temporales consultando directamente el stringel búfer usando numpy.frombuffer
:
>>> import numpy as np
>>> np.frombuffer("abcdefgh", "uint8").sum()
804
Para cadenas más pequeñas, esto es más lento que un temporal array debido a las complejidades en la maquinaria de creación de vistas de numpy. Sin embargo, para cadenas lo suficientemente grandes, la frombuffer
El enfoque comienza a dar sus frutos y, por supuesto, siempre genera menos basura. En mi máquina, el punto de corte es string tamaño de unos 200 caracteres.
Además, vea el ensayo clásico de Guido Anécdota de optimización de Python. Si bien algunas de sus técnicas específicas pueden ser obsoletas ahora, la lección general de cómo pensar sobre la optimización de Python sigue siendo bastante relevante.
Puede cronometrar los diferentes enfoques con el timeit
módulo:
$ python -m timeit -s 's = "a" * 20' 'sum(ord(ch) for ch in s)'
100000 loops, best of 3: 3.85 usec per loop
$ python -m timeit -s 's = "a" * 20' 'sum(bytearray(s))'
1000000 loops, best of 3: 1.05 usec per loop
$ python -m timeit -s 'from numpy import frombuffer; s = "a" * 20'
'frombuffer(s, "uint8").sum()'
100000 loops, best of 3: 4.8 usec per loop
Puede acelerarlo un poco (~ 40% ish, pero no tan rápido como C nativo) eliminando la creación del generador …
En vez de:
sum(ord(c) for c in string)
Hacer:
sum(map(ord, string))
Horarios:
>>> timeit.timeit(stmt="sum(map(ord, 'abcdefgh'))")
# TP: 1.5709713941578798
# JC: 1.425781011581421
>>> timeit.timeit(stmt="sum(ord(c) for c in 'abcdefgh')")
# TP: 1.7807035140629637
# JC: 1.9981679916381836
print sum(map(ord,my_string))
Esto sería lo más fácil.