Diagnóstico de cuellos de botella en su programa de Python

Performance-Evaluation-Process-z-1024x640

Algunas  aplicaciones, especialmente aquellas que requieren cargar imágenes para editarlas, por ejemplo, suelen ocasionar que todo el sistema se bloquee. Así que compartiré dos herramientas que pueden ayudar a entender y/o detener tal problemas. Estas son: Pympler y Memory-profiler

Pympler

Pympler es una herramienta para analizar el uso de memoria de su aplicación. La mayor parte es un envoltorio sobre otras aplicaciones especializadas en algún diagnóstico específico.

Utilicé dos de las herramientas que proporcionaba: Asized y Tracker.

Asized mide la memoria utilizada por el objeto pasado. Tiene varias opciones que permiten ajustar la forma en que desea que mida, pero para mí los valores predeterminados funcionen. Igual, puede ver la documentación. 

Lo usas así:

imprimir(asizeof.asized(obj, detalle=10).formato())

Esto le da el tamaño en bytes de ese objeto, para saber si algo debería haberse liberado todavía está en uso.

En mi caso, tenía una referencia a una imagen dentro de uno de mis objetos, y no me di cuenta hasta que verifiqué el tamaño de mi objeto en un par de lugares donde debería estar casi vacío.

La otra herramienta es el rastreador. Este funciona un poco diferente. Lo inicias en algún punto de tu aplicación y le pides que te dé una diferencia en otro. Imprime un informe de los objetos creados durante ese lapso y su tamaño.

Lo usas así (tomado de la documentación):

tr = rastreador.SummaryTracker()
función_sin_efectos_secundarios()
tr.print_diff()

 

En resumen, Pympler es bastante fácil de configurar y puede saber qué objetos permanecerán en la memoria para un fragmento de código determinado.

 

Perfilador de memoria

Memory-profiler , a diferencia de pympler, tiene algunas dependencias. Tuve que instalar tk y matplotlib en mi sistema, junto con psutil. Sin embargo, esta herramienta puede proporcionarle el consumo de memoria de su aplicación por línea o contra el tiempo.

Lo anterior me ayudó a encontrar dónde estaban mis picos de rendimiento. Al principio tenia algo como esto:

¿Horrible, verdad?

Tenía una función para mostrar una imagen en un widget, pero cada vez que actualizaba la imagen para mostrar, tenía una referencia a la anterior. Es fácil correlacionar esa situación con el gráfico. Simplemente seguía desperdiciando memoria.

Una vez que se sabe cuál es el problema es más fácil resolverlo (la mayoría de las veces).

Tras el ajuste, mi memoria se comporta así:

Básicamente, el widget dejó de desperdiciar mi memoria, con el máximo ahora siendo menos de la mitad en el análisis anterior.

Los «picos» están correlacionados con la forma en que estoy cargando la imagen en la aplicación. Tengo que crear una copia, cambiar su formato y pasarla al widget, pero una vez hecho eso, se libera esa memoria.

Mi aplicación ya no depende de la cantidad de imágenes.

Al final, la mayor parte de la optimización se redujo a agregar una línea de código para borrar referencias antiguas, pero las herramientas para detectar el problema fueron vitales para comprender mi problema y obtener una visión clara del rendimiento y el comportamiento de mi aplicación.