Cuando un programa Python está lento, optimizar por intuición suele desperdiciar tiempo. cProfile permite medir cuántas veces se llama cada función y cuánto tiempo consume. Con esos datos puedes concentrarte en el verdadero cuello de botella en lugar de cambiar partes que apenas influyen.
Qué es cProfile
cProfile forma parte de la biblioteca estándar y realiza perfilado determinista. Registra llamadas a funciones y calcula tiempos acumulados. La documentación oficial de profile y cProfile explica las diferencias y las opciones disponibles.
Antes de perfilar, asegúrate de que el programa sea correcto. El objetivo no es convertir código defectuoso en código defectuoso más rápido. También conviene conocer prácticas generales para corregir scripts Python lentos.
Perfilar un script desde el terminal
La forma más rápida es ejecutar:
python -m cProfile mi_script.pyLa salida incluye columnas como ncalls, tottime, percall, cumtime y el nombre de la función. tottime representa el tiempo dentro de la función sin contar subllamadas. cumtime incluye el tiempo de funciones llamadas desde ella.
Ordenar los resultados
Una salida grande es difícil de interpretar. Puedes ordenar por tiempo acumulado:
python -m cProfile -s cumulative mi_script.pyTambién se puede ordenar por tiempo interno con -s tottime. Empieza por las primeras funciones, pero revisa el contexto: una función puede consumir mucho tiempo porque se llama miles de veces, porque realiza E/S o porque ejecuta una operación costosa.
Guardar el perfil
Para analizar los datos después, guarda un archivo:
python -m cProfile -o perfil.prof mi_script.pyLuego abre el resultado con pstats:
import pstats
estadisticas = pstats.Stats("perfil.prof")
estadisticas.strip_dirs()
estadisticas.sort_stats("cumulative")
estadisticas.print_stats(20)La sección oficial sobre la clase Stats documenta filtros, ordenación y análisis de llamadas.
Perfilar una función concreta
No siempre necesitas ejecutar toda la aplicación. Puedes perfilar un punto específico:
import cProfile
def proceso():
return sum(i * i for i in range(1_000_000))
cProfile.run("proceso()", sort="cumulative")Para código más estructurado, crea un objeto Profile, habilítalo alrededor de la sección relevante y deshabilítalo después. Esto reduce ruido de inicialización.
Ejemplo de interpretación
Imagina una función llamada 100.000 veces con un tottime pequeño, pero un cumtime alto. Probablemente delega trabajo costoso a otras funciones. En cambio, una función con tottime alto consume tiempo en su propio cuerpo. Esta diferencia orienta dónde investigar.
Si el problema parece concentrarse en una operación breve, utiliza timeit para medir fragmentos de código. timeit compara pequeñas alternativas; cProfile muestra el comportamiento global.
Optimizar después de medir
Las mejoras comunes incluyen reducir llamadas repetidas, usar estructuras adecuadas, evitar conversiones innecesarias, mover cálculos constantes fuera de bucles y aprovechar funciones incorporadas. En tareas numéricas intensivas puede convenir NumPy. En operaciones de red o disco, la solución puede ser concurrencia o asincronía, no microoptimización.
Funciones, retornos y diseño
Un perfil es más útil cuando el código está dividido en funciones con responsabilidades claras. La guía de funciones en Python ayuda a estructurar bloques medibles. También debes conservar resultados correctamente con return, porque una refactorización de rendimiento no debe cambiar el comportamiento observable.
Limitaciones de cProfile
El perfilador añade sobrecarga, así que los tiempos no son una reproducción perfecta de producción. Es excelente para localizar áreas costosas, pero los números absolutos deben interpretarse con cuidado. Además, no muestra consumo de memoria; para eso se necesitan herramientas como tracemalloc o perfiles de memoria.
En aplicaciones con múltiples procesos, servicios externos o bases de datos, una ejecución local puede no reflejar la carga real. Complementa el análisis con logs, métricas y pruebas representativas.
Errores frecuentes
No perfiles una entrada demasiado pequeña, porque el ruido dominará el resultado. No optimices solo una ejecución anormal. No elijas una función únicamente por número de llamadas: muchas llamadas rápidas pueden ser aceptables. Tampoco sacrifiques claridad por una mejora mínima sin medir el beneficio.
Flujo recomendado
Primero define un escenario reproducible. Ejecuta el perfil y guarda el resultado. Ordena por tiempo acumulado, identifica una o dos áreas importantes y formula una hipótesis. Aplica un cambio pequeño, ejecuta pruebas para comprobar que el resultado sigue siendo correcto y vuelve a medir.
Cuando el proyecto depende de configuración externa, sigue la guía de variables de entorno en Python para reproducir el mismo escenario sin exponer secretos. El rendimiento se mejora con evidencia: cProfile convierte una sensación de lentitud en datos concretos y comparables.
Reducir el ruido del informe
Los perfiles pueden incluir importaciones, bibliotecas y funciones internas que no controlas. strip_dirs() acorta rutas; print_stats("mi_paquete") filtra por texto; y print_callers() ayuda a descubrir quién llama a una función costosa. Filtrar no significa ignorar dependencias: una biblioteca externa puede ser el cuello de botella, pero primero necesitas entender desde qué parte de tu código se invoca.
CPU frente a entrada y salida
Un programa puede estar lento porque calcula demasiado o porque espera red, disco o base de datos. cProfile registra el tiempo observado en las llamadas, pero la solución depende de la causa. Para CPU, busca algoritmos y estructuras mejores. Para E/S, reduce solicitudes, agrupa operaciones, utiliza caché o considera concurrencia. No añadas hilos a un cálculo intensivo esperando una mejora automática.
Comparar antes y después
Guarda el perfil inicial y registra el tiempo total del escenario. Después del cambio, ejecuta exactamente la misma entrada y configuración. Una mejora en una función no sirve si aumenta el costo en otra parte o cambia el resultado. Además del rendimiento, compara consumo de memoria y claridad. Una optimización compleja debería justificar su costo de mantenimiento.






