Cómo perfilar código Python: guía de optimización

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

El perfilado de código es un proceso sistemático de análisis del rendimiento de un programa que permite identificar cuellos de botella y optimizar el funcionamiento de la aplicación. En Python, existen numerosas herramientas para medir el tiempo de ejecución, el consumo de memoria y otras métricas críticas.

Fundamentos del perfilado de código Python

El perfilado consiste en un análisis dinámico del programa que mide:

  • el tiempo de ejecución de funciones individuales
  • la cantidad de llamadas a métodos
  • el consumo de memoria RAM
  • la carga del procesador

El objetivo principal del perfilado es identificar las secciones críticas del código que ralentizan la aplicación y requieren optimización.

Cuándo aplicar el perfilado

El perfilado es especialmente útil en los siguientes casos:

Rendimiento de la aplicación: Si el programa funciona más lento de lo esperado, el perfilado ayudará a identificar las causas de la lentitud.

Alto consumo de recursos: Cuando hay un uso excesivo de CPU o memoria RAM, el perfilado mostrará qué funciones consumen más recursos.

Preparación para producción: Antes de desplegar aplicaciones críticas, el perfilado ayuda a garantizar su eficiencia.

Optimización de algoritmos: Al trabajar con grandes volúmenes de datos o cálculos complejos, el perfilado revela algoritmos ineficientes.

Herramientas de perfilado integradas

Módulo cProfile

cProfile es el perfilador estándar de Python, incluido en el intérprete. Es ideal para un análisis general del rendimiento del programa.

import cProfile

def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

def test_function():
    result = fibonacci(30)
    return result

# Iniciar el perfilado
cProfile.run('test_function()')

El resultado del perfilado contiene métricas importantes:

  • ncalls — número total de llamadas a la función
  • tottime — tiempo de ejecución de la función sin incluir llamadas anidadas
  • percall — tiempo promedio por llamada
  • cumtime — tiempo total incluyendo todas las llamadas anidadas
  • filename:lineno(function) — ubicación de la función en el código

Módulo timeit para mediciones puntuales

Para medir el tiempo de ejecución de fragmentos pequeños de código se utiliza el módulo timeit:

import timeit

# Comparación de diferentes formas de crear una lista
list_comprehension = timeit.timeit('[i*2 for i in range(1000)]', number=1000)
map_function = timeit.timeit('list(map(lambda x: x*2, range(1000)))', number=1000)

print(f"List comprehension: {list_comprehension:.6f} seg")
print(f"Función map: {map_function:.6f} seg")

Módulo profile para análisis detallado

Un perfilador integrado alternativo, más lento que cProfile pero que proporciona información más detallada:

import profile

def complex_calculation():
    data = []
    for i in range(10000):
        data.append(i ** 2)
    return sum(data)

profile.run('complex_calculation()')

Herramientas de perfilado externas

line_profiler — perfilado línea por línea

Esta herramienta muestra el tiempo de ejecución de cada línea de código:

pip install line_profiler
@profile
def process_data():
    data = []
    for i in range(100000):  # Esta línea podría ser un cuello de botella
        data.append(i * 2)
    return sum(data)

Ejecución del perfilado línea por línea:

kernprof -l -v script.py

memory_profiler — análisis de memoria

Para monitorear el consumo de memoria de tu código:

pip install memory_profiler
from memory_profiler import profile

@profile
def memory_intensive():
    large_list = [i for i in range(1000000)]
    return sum(large_list)

py-spy — perfilado en producción

py-spy permite perfilar procesos de Python en ejecución sin necesidad de modificar el código:

pip install py-spy

Uso básico:

# Perfilar un proceso en ejecución
py-spy record -o profile.svg --pid 12345

# Ver estadísticas en tiempo real
py-spy top --pid 12345

Visualización de resultados de perfilado

SnakeViz

SnakeViz es una herramienta basada en navegador para visualizar los resultados de cProfile:

pip install snakeviz
import cProfile
import pstats

cProfile.run('test_function()', 'output.prof')

# Visualizar en el navegador
# snakeviz output.prof

Gráficos de llama (Flame Graphs)

Los gráficos de llama son una forma visual de representar el tiempo de ejecución de las funciones:

# Generar un gráfico de llama con py-spy
py-spy record -o flamegraph.svg --pid 12345

Buenas prácticas de perfilado

  • Perfilar antes de optimizar: No asumas qué parte del código es lenta; primero mide y luego optimiza.
  • Usar datos representativos: Prueba con conjuntos de datos similares a los de producción.
  • Realizar múltiples ejecuciones: Los resultados pueden variar; ejecuta varias veces para obtener un promedio.
  • Combinar herramientas: Usa cProfile para una visión general y line_profiler para un análisis detallado.
  • Documentar los resultados: Guarda los resultados del perfilado para comparar después de las optimizaciones.

Ejemplo completo: optimización de una función

import cProfile
import pstats

def slow_function():
    result = []
    for i in range(1000):
        temp = []
        for j in range(1000):
            temp.append(i * j)
        result.append(sum(temp))
    return result

# Perfilado detallado
profiler = cProfile.Profile()
profiler.enable()
slow_function()
profiler.disable()

# Mostrar resultados ordenados por tiempo acumulado
stats = pstats.Stats(profiler)
stats.sort_stats('cumtime')
stats.print_stats(10)  # Mostrar las 10 funciones más lentas

Conclusión

El perfilado de código es una habilidad esencial para cualquier desarrollador de Python que busque crear aplicaciones eficientes. Con herramientas como cProfile, timeit, line_profiler, memory_profiler y py-spy, puedes identificar y solucionar problemas de rendimiento de manera sistemática. Recuerda siempre medir antes de optimizar y utilizar los datos del perfilado para guiar tus decisiones de mejora.

Blogs

Book Recommendations