Estratégias de Caching Avançado com functools.lru_cache em Python
functools
oferece o decorator lru_cache
, que implementa um cache de tamanho limitado baseado em política LRU (Least Recently Used).O lru_cache
é extremamente útil para funções puras que são chamadas repetidamente com os mesmos parâmetros, como funções recursivas, cálculos matemáticos intensivos ou queries simuladas em memória.
1. Conceito de LRU Cache
LRU (Least Recently Used) significa que o item mais antigo e menos acessado é removido do cache quando o limite de armazenamento é atingido.
Permite balancear uso de memória e velocidade.
Evita que cache cresça indefinidamente em aplicações de longo prazo.
2. Uso Básico do lru_cache
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(35))
maxsize
define o número máximo de resultados armazenados.Funções puras são ideais: mesmos argumentos → mesmos resultados.
3. Monitorando o Cache
O decorator oferece métodos para inspeção:
print(fibonacci.cache_info())
# CacheInfo(hits=33, misses=36, maxsize=128, currsize=36)
hits
: chamadas atendidas pelo cachemisses
: chamadas computadas normalmentecurrsize
: tamanho atual do cachemaxsize
: limite do cache
Limpeza do cache
fibonacci.cache_clear() # limpa todo o cache
Útil para resetar resultados obsoletos.
4. Estratégias Avançadas
4.1 Ajustando maxsize
maxsize=None
→ cache ilimitado, útil quando se tem memória suficiente e função chamada repetidamente.Pequenos valores → menor uso de memória, mas mais recomputações.
Valores grandes → melhor performance, maior consumo de memória.
@lru_cache(maxsize=None) # cache infinito
def heavy_computation(x):
return x**2
4.2 Funções com múltiplos argumentos
lru_cache
suporta qualquer número de argumentos hashable.Para argumentos mutáveis (listas, dicts), use tuplas ou frozensets para hash seguro.
@lru_cache(maxsize=256)
def process_data(config_tuple):
return sum(config_tuple)
Evita erros de hash e garante cache consistente.
4.3 Composição de caches
É possível decorar funções auxiliares para acelerar pipelines complexos.
@lru_cache(maxsize=128)
def preprocess(x):
print(f"Preprocessing {x}")
return x*2
@lru_cache(maxsize=64)
def compute(x):
return preprocess(x) + 10
print(compute(5)) # Chama preprocess
print(compute(5)) # Usará cache de compute e preprocess
Estratégia útil em ETL e pipelines de dados complexos.
5. Caching em Funções Recursivas Complexas
O lru_cache
é perfeito para algoritmos recursivos, como Fibonacci, caminhos em grafos e DP (programação dinâmica).
@lru_cache(maxsize=None)
def caminhos(grafo, inicio, fim):
if inicio == fim:
return [[inicio]]
result = []
for vizinho in grafo.get(inicio, []):
for caminho in caminhos(grafo, vizinho, fim):
result.append([inicio] + caminho)
return result
grafo = {'A':['B','C'], 'B':['C','D'], 'C':['D'], 'D':[]}
print(caminhos(tuple(grafo.items()), 'A', 'D'))
Converte
grafo
em tuple para ser hashable, permitindo caching seguro.
6. Combinação com Paralelização
lru_cache
funciona melhor em funções puras, então pode ser combinada com ThreadPoolExecutor ou ProcessPoolExecutor para processamento paralelo seguro.
from concurrent.futures import ThreadPoolExecutor
import time
@lru_cache(maxsize=128)
def slow(x):
time.sleep(1)
return x**2
dados = range(5)
with ThreadPoolExecutor() as executor:
resultados = list(executor.map(slow, dados))
Cache evita recomputações mesmo em chamadas concorrentes.
7. Boas Práticas Profissionais
Prefira funções puras, sem efeitos colaterais, para evitar resultados inconsistentes.
Use
maxsize
adequado ao uso de memória disponível.Combine caches em pipelines modulares, acelerando cada etapa.
Documente claramente quando e como o cache é usado, principalmente em produção.
Evite caching de dados mutáveis não-hashable.
Use
cache_info()
para monitorar performance e acertos do cache.
8. Aplicações Profissionais
Algoritmos recursivos complexos (Fibonacci, caminhos, DP)
ETL e pipelines de dados (pré-processamento, normalização)
APIs que chamam funções custosas repetidamente
Testes unitários e mocks que exigem recomputações frequentes
9. Conclusão
functools.lru_cache
é uma ferramenta poderosa para melhorar performance de funções repetitivas e pesadas.Estratégias avançadas incluem ajuste de maxsize, composição de caches e caching em pipelines complexos.
Quando combinada com funções puras, paralelização e monitoramento, permite otimizar algoritmos críticos em Python sem alterar lógica do código.
Comentários
Postar um comentário