timeit y Microbenchmarks
Los microbenchmarks miden fragmentos de código pequeños con precisión. El módulo timeit elimina los errores comunes de medición (recolección de basura, sobrecarga de configuración) para obtener comparaciones justas.
Receta
import timeit
time_a = timeit.timeit("[x*x for x in range(1000)]", number=10000)
time_b = timeit.timeit("list(map(lambda x: x*x, range(1000)))", number=10000)
print(f"comprensión: {time_a:.4f}s, map: {time_b:.4f}s")Cuándo usar esto:
- Comparar dos implementaciones de la misma lógica
- Validar que una optimización realmente ayuda
- Realizar benchmarks de alternativas de la biblioteca estándar frente a alternativas de terceros
Ejemplo de Trabajo
import timeit
setup = """
from pathlib import Path
data = list(range(10000))
"""
stmt_list = "[x * 2 for x in data]"
stmt_gen = "list(x * 2 for x in data)"
t_list = timeit.timeit(stmt_list, setup=setup, number=1000)
t_gen = timeit.timeit(stmt_gen, setup=setup, number=1000)
print(f"comp. lista: {t_list:.4f}s, gen: {t_gen:.4f}s, ratio: {t_gen/t_list:.2f}x")# Línea de comandos
# python -m timeit "[x*x for x in range(1000)]"
# python -m timeit -s "import math" "math.sqrt(2)"Lo que esto demuestra:
setupse ejecuta una vez;stmtse ejecutanumberveces- Comparación justa con una configuración idéntica
- CLI
python -m timeitpara comandos rápidos de una línea - Informar la relación (ratio), no solo los tiempos absolutos
Profundización
Reglas de Benchmark
- Ejecutar en una máquina inactiva (cerrar otras aplicaciones)
- Aumentar
numberhasta que el tiempo total sea > 0.2s - Ejecutar múltiples rondas; informar la mediana, no la mejor
- Nunca realizar benchmarks de I/O o red en timeit
Errores Comunes
| Error | Solución |
|---|---|
| GC durante la medición | timeit deshabilita el GC por defecto |
| Caché fría | Calentar antes de medir |
| Modo de depuración | Realizar benchmark sin -O a menos que se mida producción |
number muy pequeño | Aumentar hasta que la resolución del temporizador sea insignificante |
Advertencias
- Realizar benchmarks de compilaciones de depuración -
-Oo la configuración de producción difieren. Solución: realizar benchmark de la configuración de implementación. - Conclusiones de una sola ejecución - el ruido domina. Solución: múltiples ejecuciones, informar la mediana y la desviación estándar.
- Comparar diferentes tamaños de entrada - cruce de O(n) vs O(n^2). Solución: realizar benchmark en tamaños de entrada realistas.
- Optimizar la ruta no "caliente" - el microbenchmark gana pero sin impacto real. Solución: perfilar primero la aplicación completa.
- Eliminación de código muerto - el compilador elimina resultados no utilizados. Solución: almacenar o usar el resultado en el bucle de benchmark.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
| pytest-benchmark | Seguimiento de regresiones en CI | Comparación rápida de un solo uso |
| cProfile | Encontrar qué hacer benchmark | Comparar dos implementaciones |
| pyperf | Benchmarks estadísticos rigurosos | Comprobaciones rápidas |
Preguntas Frecuentes
¿timeit vs time.perf_counter?
timeit para fragmentos aislados. perf_counter para la medición de funciones completas.
¿Qué número debería usar?
Aumentar hasta que el tiempo total transcurrido sea de 0.2 a 2 segundos. timeit se autocalibra con autorange.
¿Puedo hacer benchmark de código asíncrono?
Usar asyncio.run() en setup/stmt o herramientas de benchmark asíncronas dedicadas.
¿Cómo hago benchmark con argumentos?
Usar setup para definir datos; referenciarlos en la cadena stmt.
¿Es timeit seguro para hilos (thread-safe)?
Cada llamada es independiente. Para código con hilos, realizar benchmark del escenario concurrente completo por separado.
¿Ejemplos de python -m timeit?
python -m timeit "sum(range(1000))" se ejecuta con repeticiones autocalibradas.
¿Cómo evito la interferencia del GC?
timeit deshabilita el GC durante la medición por defecto.
¿Debería usar %timeit en Jupyter?
Conveniente para la exploración. Usar el módulo timeit para scripts reproducibles.
¿Cómo comparto los resultados del benchmark?
Confirmar un script de benchmark con number fijo y documentar el hardware/SO.
¿Cuándo es engañoso el microbenchmarking?
Cuando el fragmento no es el punto crítico de la aplicación. Perfilar primero.
Relacionados
- Conceptos Básicos de Rendimiento - mentalidad de medición
- cProfile y Profilers - encontrar puntos críticos
- Mejores Prácticas de Rendimiento - cuándo optimizar
- Vectorización con NumPy - benchmarks numéricos
Versiones de Stack: Esta página fue escrita para Python 3.14.0, FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.