De acuerdo con la encuesta de Stackoverflow de 2019, el lenguaje de programación Python obtuvo una aprobación del 73,1% entre los desarrolladores. Ocupa el segundo lugar después de Rust y continúa dominando la Ciencia de Datos y el Aprendizaje Automático(ML).
Python es el favorito de los desarrolladores. Es un lenguaje de alto nivel conocido por su robustez y su filosofía central: simplicidad sobre complejidad. Sin embargo, el rendimiento de la aplicación Python es otra historia. Al igual que cualquier otra aplicación, tiene su parte de problemas de rendimiento.
La mayoría de las veces, las herramientas de APM, como Retrace, pueden ayudar a resolver problemas de rendimiento de las aplicaciones. Pero, ¿qué pasa si su aplicación Python se ha estado ejecutando durante cuatro horas y el servidor se ha quedado sin memoria? Ese es un problema específico que involucra recursos de memoria.
Se llama pérdida de memoria. Los desarrolladores necesitan encontrar al culpable. Es entonces cuando entran en juego los perfiladores de memoria Python.
Exploremos más a fondo.
¿Qué son los perfiladores de memoria Python?
Las aplicaciones de creación de perfiles siempre implican problemas como CPU, memoria, etc. Sin embargo, las aplicaciones Python son propensas a problemas de administración de memoria. Esto se debe principalmente a que Python se aplica a aplicaciones de Ciencia de Datos y Aprendizaje automático y funciona con grandes cantidades de datos. Además, Python se basa en su sistema de gestión de memoria por defecto, en lugar de dejarlo en manos del usuario.
Como el código Python funciona dentro de contenedores a través de un marco de procesamiento distribuido, cada contenedor contiene una cantidad fija de memoria. Si la ejecución de código supera el límite de memoria, el contenedor terminará. Esto es cuando el desarrollo experimenta errores de memoria.
Sin embargo, no siempre es el caso. Hay casos en los que los desarrolladores no saben lo que está pasando. Tal vez un objeto está colgando de una referencia cuando se supone que no debe estar y se acumula con el tiempo. Una vez que alcanza su punto máximo, se producen problemas de memoria.
La solución rápida es aumentar la asignación de memoria. Sin embargo, no es práctico, ya que esto puede dar lugar a un desperdicio de recursos. Además, puede poner en peligro la estabilidad de la aplicación debido a picos de memoria impredecibles.
Por lo tanto, necesitamos la ayuda de los perfiladores de memoria Python. El propósito de los perfiladores de memoria Python es encontrar fugas de memoria y optimizar el uso de memoria en sus aplicaciones Python. Estos tipos de perfiladores de memoria Python entienden la eficiencia de espacio del código y los paquetes utilizados.
Principales perfiladores de memoria de Python
Aunque Python gestiona automáticamente la memoria, necesita herramientas porque los trabajos de Python de larga duración consumen mucha memoria. En la mayoría de los casos, estos trabajos no devolverán la memoria al sistema operativo hasta que finalice el proceso, incluso si ejecuta correctamente la recolección de basura.
Aquí hay una lista de perfiladores de memoria Python conocidos:
Pympler
Jean Brouwers, Ludwig Haehne y Robert Schuppenies construyeron Pympler en agosto de 2008. Introdujeron el proceso de pympling, en el que Pympler obtiene detalles del tamaño y la vida útil de los objetos Python.
El generador de perfiles de memoria Python de Pympler analiza el comportamiento de la memoria del objeto Python dentro de una aplicación en ejecución. Proporciona una solución de generación de perfiles de memoria Python completa e independiente. Además, proyecta posibles errores en el comportamiento de tiempo de ejecución, como la hinchazón de memoria y otras «pimplas».»
Hay tres módulos separados dentro de Pympler.
- El módulo asizeof proporciona la información del tamaño del objeto Python.
- El módulo mupy se encarga de la supervisión en línea de una aplicación Python.
- El módulo de seguimiento de clases proporciona análisis fuera de línea de la vida útil de los objetos Python seleccionados.
Primero, usemos asizeof para investigar cuánta memoria consumen ciertos objetos Python.
>>> from pympler import asizeof
>>> obj =
>>> asizeof.asizeof(obj)
>>> print (asizeof.asized(obj, detail=1).format())
size=192 plana=48
(6, 4) tamaño=64 plana=32
‘yo’ size=plana 32=32
3 size=16 plana=16
tamaño 2=16 plana=16
1 size=16 plana=16
en Segundo lugar, vamos a implementar el muppy módulo:
>>> desde pympler de importación muppy
>>> allObjects = muppy.get_objects()
>>> len(allObjects)
>>> desde pympler resumen de la importación
>>> I = resumen.resumen(allObjects)
>>> resumen.print_(sum)
types | | # objects | | total size |
========================== | | =========== | | ============ |
str | | 13262 | | 1.01 MB |
dict | | 2120 | | 659.99 KB |
code | | 3362 | | 343.73 KB |
list | | 2587 | | 247.46 KB |
type | | 639 | | 242.61 KB |
tuple | | 2069 | | 58.83 KB |
set | | 86 | | 44.57 KB |
wrapper_descriptor | | 1247 | | 43.84 KB |
builtin_function_or_method | | 1014 | | 35.65 KB |
method_descriptor | | 937 | | 32.94 KB |
abc.ABCMeta | | 66 | | 32.38 KB |
weakref | | 818 | | 28.76 KB |
int | | 1612 | | 24.72 KB |
getset_descriptor | | 555 | | 17.34 KB |
frozenset | | 90 | | 16.87 KB |
Aquí, usted puede ver todos los objetos de Python en un montón de uso de la muppy módulo. Puede llamar a otro resumen y compararlo para comprobar si algunas matrices tienen fugas de memoria. Obtenga más información sobre el módulo muppy aquí.
El tercer módulo del generador de perfiles Pympler es el Rastreador de clases. Rastrea la vida útil de los objetos de ciertas clases. Thus, it provides insight into instantiation patterns and helps developers understand how specific objects contribute to the memory footprint in the long run.
>>> tr = classtracker.ClassTracker()
>>> tr.track_class(Document)
>>> tr.create_snapshot(description=’Snapshot 1′)
>>> doc = create_document()
>>> tr.create_snapshot(description=’Snapshot 2′)
>>> tr.stats.print_summary ()
SUMMARY RESUMEN ———————-
Instantánea 1 activo 0 B pct promedio
Instantánea 2 activo 0 B pct promedio
—————————
Para obtener más información sobre el Rastreador de clases, haga clic aquí.
Guppy3
Guppy3 (también conocido como Heapy) es un entorno de programación Python y un conjunto de herramientas de análisis de montones. Es un paquete que contiene los siguientes subpaquetes:
- etc – Este es un módulo de soporte que tiene el módulo de protocolo Glue.
- gsl – El subpaquete que contiene la implementación del Lenguaje de especificación Guppy. Crea documentos y pruebas a partir de una fuente común.
- heapy: El conjunto de herramientas de análisis de montones proporciona información de objetos sobre el montón y muestra la información.conjuntos
- : Contiene conjuntos de bits y conjuntos de nodos.
Guppy3 es un fork de Guppy-PE y fue construido por Sverker Nilsson para Python 2.
Nota: El uso de este generador de perfiles de memoria Python requiere Python 3.5, 3.6, 3.7 o 3.8. Este paquete solo funciona para CPython. Por lo tanto, PyPy y otras implementaciones de compilador de Python no son compatibles. Además, para usar el navegador gráfico, necesita Tkinter. Además, el roscado debe estar disponible cuando se utiliza un monitor remoto.
Aquí le mostramos cómo aprovechar este generador de perfiles de memoria Python. Puede tomar una instantánea del montón antes y después de un proceso crítico. A continuación, compare la memoria total e identifique los posibles picos de memoria involucrados en objetos comunes.
>>> from guppy import hpy
>>> h=hpy()
>>> h.heap()
Partition of a set of 34090 objects. Total size = 2366226 bytes.
Index | Count | % | Size | % | Cumulative | % | Kind (class / dict of class) |
0 | 10279 | 30 | 666873 | 28 | 666873 | 28 | str |
1 | 4697 | 14 | 259576 | 11 | 926449 | 39 | bytes |
2 | 2413 | 7 | 251684 | 11 | 1178133 | 50 | types.CodeType |
3 | 6825 | 20 | 238084 | 10 | 1416217 | 60 | tuple |
4 | 448 | 1 | 174868 | 7 | 1591085 | 67 | type |
5 | 2208 | 6 | 150144 | 6 | 1741229 | 74 | function |
6 | 448 | 1 | 130964 | 6 | 1872193 | 79 | dict of type |
7 | 94 | 0 | 83532 | 4 | 1955725 | 83 | dict of module |
8 | 242 | 1 | 56524 | 2 | 2012249 | 85 | dict (no owner) |
9 | 1133 | 3 | 40788 | 2 | 2053037 | 87 | types.WrapperDescriptorType |
<118 more rows. Type e.g. ‘_.more’ to view.>
Memory Profiler
Memory Profiler is a pure Python module that uses the psutil module. Supervisa el consumo de memoria de un proceso de trabajo de Python. Además, realiza un análisis línea por línea del consumo de memoria de la aplicación.
El modo de uso de memoria línea por línea funciona de la misma manera que line_profiler.
- Decora la función que desea perfilar utilizando la función @ profile.
- Puede ejecutar el script con un script especial. Por ejemplo, utilice argumentos específicos para el intérprete de Python.
En el siguiente ejemplo, vamos a tener una función simple llamada my_func. Esta función crea una lista con un rango especificado.
@profile
def my_func():
a=
for i in range(1000):
a.append(i)
my_func()
This outputs:
Line # | Mem Usage | Increment | Line Contents |
1 | 13.859 MiB | 13.859 MiB | @profile |
2 | def my_func(): | ||
3 | 13.859 MiB | 0.000 MiB | a= |
4 | 13.859 MiB | 0.000 MiB | for i in range(1000): |
5 | 13.859 MiB | 0.000 MiB | un.append(i) |
La primera columna es el número de línea en el perfil de código. El uso de Mem es el uso de memoria del intérprete de Python después de cada ejecución de código. La tercera columna (Incremento) representa la diferencia en memoria de la línea actual a la última. La última columna (Contenido de línea) muestra los códigos perfilados.
To see how this Python memory profiler works, let’s change the range value to 1000000 in the function above and execute it. Here is the output:
Line # | Mem usage | Increment | Line Contents |
1 | 13.844 MiB | 13.844 MiB | @profile |
2 | def my_func(): | ||
3 | 13.844 MiB | 0.000 MiB | a= |
4 | 33.387 MiB | 0.016 MiB | for i in range(1000000): |
5 | 33.387 MiB | 0.293 MiB | un.append(i) |
la Línea 4 y 5 muestran un aumento en el uso de la memoria, demostrando que el analizador realiza una línea-por-línea de análisis de consumo de memoria.
Fil
Fil profiler es un generador de perfiles de memoria Python de código abierto. Es adecuado para aplicaciones de procesamiento de datos y computación científica. Actualmente, todavía está en la etapa de desarrollo y se ejecuta solo en Linux y macOS.
La mayoría de los científicos de datos y desarrolladores de Python enfrentan problemas de memoria con la canalización de datos de Python. Cuando se utiliza demasiada memoria, es difícil identificar exactamente a dónde va toda la memoria.
Por ejemplo, citemos dos escenarios:
Servidores
Como los servidores se ejecutan sin parar, las fugas de memoria a menudo son la causa del fallo de rendimiento. Los desarrolladores descuidan pequeñas cantidades de pérdida de memoria, ya que la mayoría de los servidores procesan pequeñas cantidades de datos a la vez. Sin embargo, estos pueden sumar decenas de miles de llamadas. Como resultado, esto podría crear graves problemas de producción con el tiempo.
Canalizaciones de datos
Al procesar grandes trozos de datos, los picos en el uso de memoria traen grandes amenazas a las canalizaciones de datos. Por ejemplo, si tu aplicación usa 1 GB de RAM durante bastante tiempo y de repente necesita 16 GB de RAM. Hay una gran necesidad de identificar qué causa picos repentinos de memoria.
Ese es el objetivo principal de Fil: diagnosticar picos de uso de memoria, independientemente de la cantidad de datos que se procesen. Señala dónde está exactamente el pico de uso de memoria y qué código es responsable de ese pico.
Aunque existen perfiles de memoria Python que miden el uso de memoria, tiene limitaciones. Una de ellas es tratar con grandes cantidades de procesamiento de datos por lotes. Las aplicaciones de Python son en su mayoría aplicaciones de procesamiento por lotes en las que leen datos constantemente, los procesan y generan el resultado.
Nuestro siguiente generador de perfiles responde a ese problema.
Blackfire
Para un lenguaje altamente dinámico como Python, la mayoría de los desarrolladores experimentan problemas de memoria durante la implementación. Esto conduce a cierta confusión en cuanto a lo que sucede con el uso de la memoria. Los desarrolladores tienden a realizar optimizaciones, pero no tienen las herramientas adecuadas para usar.
Blackfire es un generador de perfiles de memoria Python propietario (tal vez el primero. Utiliza el administrador de memoria de Python para rastrear cada bloque de memoria asignado por Python, incluidas las extensiones C. Blackfire es nuevo en el campo y tiene como objetivo resolver problemas en fugas de memoria, como:
- objetos grandes en memoria que no se liberan
- ciclos de referencia
- recuento de referencias inválido en extensiones C que causan fugas de memoria
- picos repentinos de memoria
Con estos casos de uso, Blackfire asegura a los usuarios que tiene una sobrecarga muy limitada y no afecta a los usuarios finales porque mide el consumo de memoria de la aplicación Python en el nivel de llamada a la función.
Blackfire Python memory profiler utiliza la API PyMem_SetAllocator para rastrear asignaciones de memoria como tracemalloc. En la actualidad, Blackfire es compatible con las versiones de Python 3.5 y superiores. Puede visitar su sitio para obtener más información.
Creación de perfiles con retroceso
Si está trabajando con Python, de alguna manera experimenta que no libera memoria de inmediato al sistema operativo. Por lo tanto, lo ejecuta en un proceso separado para asegurarse de que la memoria se libera después de ejecutar un fragmento de código. Esto se hace a través de un enfoque útil llamado «caso de prueba pequeño».»Este proceso permite ejecutar solo el código de fuga de memoria en cuestión.
Cuando se trate de grandes cantidades de datos, utilice un subconjunto de los datos muestreados aleatoriamente. Además, ejecute tareas de uso intensivo de memoria en procesos separados y use depuradores para agregar referencias a objetos. Sin embargo, tenga en cuenta que el uso de un depurador de punto de interrupción, como pdb, permite que los objetos creados y referenciados manualmente desde el depurador permanezcan en el perfil de memoria. Esto dará lugar a una falsa sensación de fugas de memoria, ya que los objetos no se liberan a tiempo. Además, considere buscar paquetes que puedan tener fugas. Hay bibliotecas de Python que podrían tener fugas de memoria.
Por ahora, ya sabe cómo funcionan los perfiladores de memoria de Python y los problemas de memoria comunes con Python. Pero herramientas como el rastreo con registro centralizado, el seguimiento de errores y la creación de perfiles de código pueden ayudarlo a diagnosticar problemas de Python a mayor escala. Volver a rastrear desde Stackify te ayudará a lidiar con cualquier tipo de problemas de rendimiento y a mantener tu código funcionando bien.
¡Comience su prueba de rastreo GRATUITA de 14 días hoy mismo!