Python Language
Optimización del rendimiento
Buscar..
Observaciones
Cuando intente mejorar el rendimiento de un script de Python, en primer lugar debería poder encontrar el cuello de botella de su script y tener en cuenta que ninguna optimización puede compensar una mala elección en las estructuras de datos o una falla en el diseño de su algoritmo. La identificación de los cuellos de botella de rendimiento se puede hacer mediante la creación de perfiles de su script. En segundo lugar, no intente optimizar demasiado pronto su proceso de codificación a expensas de la legibilidad / diseño / calidad. Donald Knuth hizo la siguiente declaración sobre la optimización:
"Debemos olvidarnos de las pequeñas eficiencias, digamos que aproximadamente el 97% de las veces: la optimización prematura es la raíz de todo mal. Sin embargo, no debemos dejar pasar nuestras oportunidades en ese 3% crítico ".
Código de perfil
En primer lugar, debe poder encontrar el cuello de botella de su script y tener en cuenta que ninguna optimización puede compensar una mala elección en la estructura de datos o una falla en el diseño de su algoritmo. En segundo lugar, no intente optimizar demasiado pronto su proceso de codificación a expensas de la legibilidad / diseño / calidad. Donald Knuth hizo la siguiente declaración sobre la optimización:
"Debemos olvidarnos de las pequeñas eficiencias, digamos que aproximadamente el 97% de las veces: la optimización prematura es la raíz de todo mal. Sin embargo, no debemos dejar pasar nuestras oportunidades en ese 3% crítico".
Para perfilar su código tiene varias herramientas: cProfile
(o el profile
más lento) de la biblioteca estándar, line_profiler
y timeit
. Cada uno de ellos tiene un propósito diferente.
cProfile
es un generador de perfiles determinístico: se controlan los eventos de llamada de función, retorno de función y excepción, y se realizan intervalos precisos para los intervalos entre estos eventos (hasta 0.001s). La documentación de la biblioteca ([ https://docs.python.org/2/library/profile.html◆◆1]) nos proporciona un caso de uso simple
import cProfile
def f(x):
return "42!"
cProfile.run('f(12)')
O si prefiere envolver partes de su código existente:
import cProfile, pstats, StringIO
pr = cProfile.Profile()
pr.enable()
# ... do something ...
# ... long ...
pr.disable()
sortby = 'cumulative'
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
print s.getvalue()
Esto creará resultados que se parecen a la tabla a continuación, donde puede ver rápidamente dónde pasa su programa la mayor parte de su tiempo e identificar las funciones para optimizar.
3 function calls in 0.000 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 <stdin>:1(f)
1 0.000 0.000 0.000 0.000 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
El módulo line_profiler
([ https://github.com/rkern/line_profilerI [ ]] es útil para tener un análisis línea por línea de su código. Obviamente, esto no es manejable para scripts largos, pero está dirigido a fragmentos. Consulte la documentación para más detalles. La forma más fácil de comenzar es usar el script kernprof tal como se explica en la página del paquete, tenga en cuenta que deberá especificar manualmente la función (es) que desea perfilar.
$ kernprof -l script_to_profile.py
kernprof creará una instancia de LineProfiler y la insertará en el espacio de nombres __builtins__
con el perfil de nombre. Se ha escrito para ser utilizado como decorador, por lo que en su script, decora las funciones que desea perfilar con @profile
.
@profile
def slow_function(a, b, c):
...
El comportamiento predeterminado de kernprof es colocar los resultados en un archivo binario script_to_profile.py.lprof
. Puede decirle a kernprof que vea inmediatamente los resultados formateados en el terminal con la opción [-v / - ver]. De lo contrario, puede ver los resultados más tarde así:
$ python -m line_profiler script_to_profile.py.lprof
Finalmente, timeit
proporciona una forma sencilla de probar un forro o una pequeña expresión tanto desde la línea de comandos como desde el shell de python. Este módulo responderá preguntas como, ¿es más rápido hacer una lista de comprensión o usar la list()
integrada list()
al transformar un conjunto en una lista? Busque la palabra clave de setup
o la opción -s
para agregar el código de configuración.
>>> import timeit
>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.8187260627746582
desde una terminal
$ python -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 40.3 usec per loop