Puede que Python no sea el lenguaje más rápido, pero a menudo es lo suficientemente rápido. Y Python es ideal cuando el tiempo del programador importa más que el tiempo de la CPU.
Dicho esto, si una aplicación de Python determinada está retrasada, no está obligado a aguantarla. Las herramientas incluidas con la instalación estándar del intérprete de Python pueden proporcionarle comentarios detallados sobre qué partes de su programa son lentas y ofrecer algunas sugerencias sobre cómo acelerarlas.
Cómo utilizar cProfile
El cProfile
módulo recopila estadísticas sobre el tiempo de ejecución de un programa Python. Puede informar sobre cualquier cosa, desde toda la aplicación hasta una sola declaración o expresión.
Aquí hay un ejemplo de juguete de cómo usar cProfile
:
def add (x, y): x + = str (y) return x def add_2 (x, y): if y% 20000 == 0: z = [] para q en el rango (0,400000): z.append ( q) def main (): a = [] para n en el rango (0,200000): add (a, n) add_2 (a, n) if __name__ == '__main__': import cProfile cProfile.run ('main ( ) ')
Este ejemplo ejecuta la main()
función de la aplicación y analiza el rendimiento main()
y todas las main()
llamadas. También es posible analizar solo una parte de un programa, pero el uso más común para los principiantes es perfilar todo el programa.
Ejecute el ejemplo anterior y será recibido con algo como el siguiente resultado:

Lo que se muestra aquí es una lista de todas las llamadas a funciones realizadas por el programa, junto con estadísticas sobre cada una:
- En la parte superior (primera línea en azul), vemos el número total de llamadas realizadas en el programa perfilado y el tiempo total de ejecución. También puede ver una figura para "llamadas primitivas", es decir, llamadas no recursivas o llamadas realizadas directamente a una función que, a su vez, no se llaman a sí mismas más abajo en la pila de llamadas.
- ncalls : número de llamadas realizadas. Si ve dos números separados por una barra, el segundo número es el número de llamadas primitivas para esa función.
- tottime : tiempo total empleado en la función, sin incluir las llamadas a otras funciones.
- percall : tiempo promedio por llamada para tottime , que se obtiene tomando tottime y dividiéndolo por ncalls .
- cumtime : tiempo total empleado en la función, incluidas las llamadas a otras funciones.
- percall (# 2): tiempo promedio por llamada para cumtime ( cumtime dividido por ncalls ).
- filename: lineno : el nombre del archivo, el número de línea y el nombre de la función para la llamada en cuestión.
Cómo modificar los informes de cProfile
De forma predeterminada, cProfile
ordena su salida por "nombre estándar", lo que significa que ordena por el texto en la columna de la derecha (nombre de archivo, número de línea, etc.).
El formato predeterminado es útil si desea un informe general de arriba hacia abajo de cada llamada de función como referencia. Pero si está tratando de llegar al fondo de un cuello de botella, es probable que desee enumerar primero las partes del programa que más tiempo requieren.
Podemos producir estos resultados invocando de forma cProfile
un poco diferente. Observe cómo la parte inferior del programa anterior se puede reelaborar para ordenar las estadísticas por una columna diferente (en este caso ncalls
):
if __name__ == '__main__': importar cProfile, pstats profiler = cProfile.Profile () profiler.enable () main () profiler.disable () stats = pstats.Stats (profiler) .sort_stats ('ncalls') stats.print_stats ()
Los resultados se verán así:

Así es como funciona todo esto:
- En lugar de ejecutar un comando a través de
cProfile.run()
, lo que no es muy flexible, creamos un perfilado objeto ,profiler
. - Cuando queremos perfilar alguna acción, primero llamamos
.enable()
a la instancia del objeto generador de perfiles, luego ejecutamos la acción y luego llamamos.disable()
. (Esta es una forma de perfilar solo una parte de un programa). - El
pstats
módulo se utiliza para manipular los resultados recopilados por el objeto generador de perfiles e imprimir esos resultados.
La combinación de un objeto de generador de perfiles y pstats
nos permite manipular los datos de perfil capturados, por ejemplo, para ordenar las estadísticas generadas de manera diferente. En este ejemplo, el uso .sort_stats('ncalls')
ordena las estadísticas por ncalls
columna. Hay otras opciones de clasificación disponibles.
Cómo utilizar los resultados de cProfile para la optimización
Las opciones de clasificación disponibles para la cProfile
salida nos permiten detectar posibles cuellos de botella de rendimiento en un programa.
ncalls
La primera y más importante información con la que puede desenterrar cProfile
es qué funciones se llaman con más frecuencia, a través de la ncalls
columna.
En Python, el mero hecho de realizar una llamada a una función genera una sobrecarga relativamente grande. Si se llama a alguna función repetidamente en un bucle cerrado, incluso si no es una función de larga duración, se garantiza que afectará el rendimiento.
En el ejemplo anterior, la función add
(y la función add_2
) se llama repetidamente en un bucle. Mover el bucle a la add
función en sí, o incluir la add
función por completo, solucionaría este problema.
tottime
Otra estadística útil detalla las funciones que el programa dedica la mayor parte de su tiempo a ejecutar, a través de la tottime
columna.
En el ejemplo anterior, la add_2
función usa un bucle para simular algunos cálculos costosos, lo que lleva su tottime
puntaje a la cima. Cualquier función con una tottime
puntuación alta merece una mirada de cerca, especialmente si se llama muchas veces o en un bucle cerrado.
Tenga en cuenta que siempre debe considerar el contexto en el que se utiliza la función. Si una función tiene un valor alto tottime
pero solo se llama una vez, por ejemplo, solo cuando se inicia el programa, es menos probable que sea un cuello de botella. Sin embargo, si está tratando de reducir el tiempo de inicio, querrá saber si una función llamada al inicio hace que todo lo demás espere.
Cómo exportar datos de cProfile
Si desea utilizar cProfile
las estadísticas generadas de forma más avanzada, puede exportarlas a un archivo de datos:
stats = pstats.Stats (generador de perfiles) stats.dump_stats ('/ ruta / a / archivo_estad.dat')
Este archivo se puede volver a leer utilizando el pstats
módulo, luego se puede ordenar o mostrar con pstats
. Los datos también pueden ser reutilizados por otros programas. Dos ejemplos:
pyprof2calltree
presenta visualizaciones detalladas del gráfico de llamadas del programa y las estadísticas de uso de los datos del perfil. Este artículo proporciona un ejemplo detallado del mundo real de su uso.snakeviz
también genera visualizaciones a partir de loscProfile
datos, pero utiliza una representación diferente para los datos: un “sunburst” en lugar del gráfico de “llama” de pyprof2calltree.
Más allá de cProfile para la creación de perfiles de Python
cProfile
no es la única forma de perfilar una aplicación Python. cProfile
es sin duda una de las formas más convenientes, dado que se incluye con Python. Pero otros merecen atención.
Un proyecto, py-spy
crea un perfil para una aplicación Python al muestrear su actividad de llamada. py-spy
se puede usar para examinar una aplicación Python en ejecución sin tener que detenerla y reiniciarla, y sin tener que alterar su código base, por lo que se puede usar para perfilar aplicaciones implementadas. py-spy
también genera algunas estadísticas sobre la sobrecarga incurrida por el tiempo de ejecución de Python (por ejemplo, sobrecarga de recolección de basura), que cProfile
no es así.