Caching & Memoization
Caching armazena resultados computados para reutilização. functools.lru_cache lida com memoization no processo; Redis/Memcached lidam com caches compartilhados entre processos.
Receita
from functools import lru_cache
@lru_cache(maxsize=128)
def expensive_lookup(key: str) -> dict:
return fetch_from_database(key)Quando usar isso:
- Funções puras chamadas repetidamente com os mesmos argumentos
- I/O caro (banco de dados, HTTP) com resultados estáveis
- Dados de configuração ou referência que mudam com pouca frequência
Exemplo de Trabalho
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"]
# Primeira chamada: requisição HTTP
# Chamadas subsequentes: em cache
rate1 = get_exchange_rate("EUR")
rate2 = get_exchange_rate("EUR") # cache hit
print(get_exchange_rate.cache_info())
# CacheInfo(hits=1, misses=1, maxsize=256, currsize=1)# Cache TTL com 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)O que isso demonstra:
lru_cachepara funções puras de reutilização ilimitadacache_info()monitora a taxa de acertos- Cache TTL para dados que expiram
- Resultados de API externos em cache para reduzir latência e carga
Mergulho Profundo
Camadas de Cache
| Camada | Ferramenta | Escopo |
|---|---|---|
| No processo | lru_cache, cachetools | Processo único |
| Compartilhado | Redis, Memcached | Todas as instâncias do aplicativo |
| HTTP | CDN, Cache-Control | Cliente e borda |
| Framework | FastAPI @lru_cache em dependências | Por worker |
Invalidação
get_exchange_rate.cache_clear() # invalidação manualArmadilhas
- Cache de valores de retorno mutáveis - o chamador muta o cache. Correção: retorne cópias ou tipos imutáveis.
- Sem TTL em lru_cache - dados obsoletos para sempre. Correção: cachetools TTLCache ou Redis com expiração.
- Cache de funções com efeitos colaterais - resultados incorretos, gravações perdidas. Correção: cache apenas leituras puras.
- Cache ilimitado - vazamento de memória. Correção: sempre defina
maxsize. - Argumentos não hasheáveis em chaves de cache - TypeError. Correção: converta para tipos hasheáveis ou use chave de cache personalizada.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Pré-computação antecipada | Dados mudam raramente | Entradas dinâmicas |
| Cache de consulta de banco de dados | Nível ORM | Controle em nível de aplicativo necessário |
| Sem cache | Dados sempre frescos | Consultas caras repetidas |
FAQs
lru_cache vs Redis?
lru_cache para funções puras em um único processo. Redis para cache compartilhado entre múltiplas instâncias.
Como faço cache de funções assíncronas?
Pacote async_lru ou dicionário manual com trava asyncio.
Qual maxsize?
Comece com 128-256. Monitore a taxa de acertos em cache_info(); ajuste.
Como faço cache de respostas FastAPI?
@lru_cache em funções de dependência. Cache HTTP com cabeçalhos Cache-Control para clientes.
Cache stampede?
Use trava por chave ou padrão stale-while-revalidate para chaves populares.
Posso fazer cache de métodos de instância?
Sim, mas o cache é por método, não por instância. Considere functools em uma função autônoma.
Como testo código em cache?
func.cache_clear() na limpeza de teste. Ou simule a fonte de dados subjacente.
Cache Django?
django.core.cache com backend Redis. @cache_page para cache de visualização.
Quando o caching é errado?
Transações financeiras, dados em tempo real, dados por usuário sensíveis à segurança sem isolamento de chave.
Como monitoro a taxa de acertos do cache?
cache_info() para lru_cache. INFO stats do Redis para caches compartilhados.
Relacionados
- Fundamentos de Performance - introdução ao lru_cache
- Profiling de Memória - custo de memória do cache
- Assincronismo e Concorrência para Throughput - cache assíncrono
- Injeção de Dependência FastAPI - dependências em cache
Versões das Pilhas: Esta página foi 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+, e uv 0.6+.