Almacenamiento en caché y memorización
El almacenamiento en caché guarda resultados calculados para su reutilización. functools.lru_cache maneja la memorización dentro del proceso; Redis/Memcached manejan cachés compartidas entre procesos.
Receta
from functools import lru_cache
@lru_cache(maxsize=128)
def expensive_lookup(key: str) -> dict:
return fetch_from_database(key)Cuándo usar esto:
- Funciones puras llamadas repetidamente con los mismos argumentos
- E/S costosa (base de datos, HTTP) con resultados estables
- Datos de configuración o de referencia que cambian con poca frecuencia
Ejemplo de trabajo
from functools import lru_cache
import httpx
@lru_cache(maxsize=256)
def get_exchange_rate(currency: str) -> float:
response = httpx.get(f"https://api.example/rates/{currency}")
response.raise_for_status()
return response.json()["rate"]
# Primera llamada: solicitud HTTP
# Llamadas posteriores: en caché
rate1 = get_exchange_rate("EUR")
rate2 = get_exchange_rate("EUR") # acierto de caché
print(get_exchange_rate.cache_info())
# CacheInfo(hits=1, misses=1, maxsize=256, currsize=1)# Caché TTL con cachetools
from cachetools import TTLCache, cached
cache = TTLCache(maxsize=100, ttl=300)
@cached(cache)
def get_user(user_id: int) -> dict:
return db.query(user_id)Lo que esto demuestra:
lru_cachepara funciones puras de reutilización ilimitadacache_info()monitoriza la tasa de aciertos- Caché TTL para datos que expiran
- Resultados de API externas en caché para reducir la latencia y la carga
Profundización
Capas de caché
| Capa | Herramienta | Ámbito |
|---|---|---|
| Dentro del proceso | lru_cache, cachetools | Proceso único |
| Compartido | Redis, Memcached | Todas las instancias de la aplicación |
| HTTP | CDN, Cache-Control | Cliente y borde |
| Framework | FastAPI @lru_cache en dependencias | Por trabajador |
Invalidación
get_exchange_rate.cache_clear() # invalidación manualErrores comunes
- Almacenar en caché valores de retorno mutables - el llamador muta la caché. Solución: devolver copias o tipos inmutables.
- Sin TTL en lru_cache - datos obsoletos para siempre. Solución:
cachetools.TTLCacheo Redis con caducidad. - Almacenar en caché funciones con efectos secundarios - resultados incorrectos, escrituras omitidas. Solución: almacenar en caché solo lecturas puras.
- Caché sin límites - fuga de memoria. Solución: establecer siempre
maxsize. - Argumentos no hasheables en claves de caché -
TypeError. Solución: convertir a tipos hasheables o usar una clave de caché personalizada.
Alternativas
| Alternativa | Usar cuándo | No usar cuándo |
|---|---|---|
| Precomputación anticipada | Los datos cambian raramente | Entradas dinámicas |
| Caché de consultas de base de datos | Nivel ORM | Se necesita control a nivel de aplicación |
| Sin caché | Los datos siempre están frescos | Búsquedas costosas repetidas |
Preguntas frecuentes
¿lru_cache vs Redis?
lru_cache para funciones puras de un solo proceso. Redis para caché compartida entre múltiples instancias.
¿Cómo almaceno en caché funciones asíncronas?
Paquete async_lru o diccionario manual con bloqueo asyncio.
¿Qué `maxsize`?
Empezar con 128-256. Monitorizar la tasa de aciertos de cache_info(); ajustar.
¿Cómo almaceno en caché respuestas de FastAPI?
@lru_cache en funciones de dependencia. Almacenamiento en caché HTTP con encabezados Cache-Control para clientes.
¿Problema de estampida de caché (cache stampede)?
Usar un bloqueo por clave o el patrón "stale-while-revalidate" para claves populares.
¿Puedo almacenar en caché métodos de instancia?
Sí, pero la caché es por método, no por instancia. Considere functools en una función independiente.
¿Cómo pruebo el código en caché?
func.cache_clear() en la limpieza de pruebas. O simular la fuente de datos subyacente.
¿Caché de Django?
django.core.cache con backend Redis. @cache_page para caché de vistas.
¿Cuándo es incorrecto el almacenamiento en caché?
Transacciones financieras, datos en tiempo real, datos por usuario sensibles a la seguridad sin aislamiento de claves.
¿Cómo monitorizo la tasa de aciertos de la caché?
cache_info() para lru_cache. INFO stats de Redis para cachés compartidas.
Relacionado
- Conceptos básicos de rendimiento - introducción a
lru_cache - Análisis de memoria - coste de memoria de la caché
- Asincronía y concurrencia para el rendimiento - caché asíncrona
- Inyección de dependencias en FastAPI - dependencias en caché
Versiones de pila: Esta página se escribió 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+.