Resposta A: Anthropic Claude Sonnet 5
import threading
import time
from collections import OrderedDict
from typing import Callable, TypeVar, Generic, Hashable, Optional, Any
K = TypeVar("K", bound=Hashable)
V = TypeVar("V")
class _InFlight(Generic[V]):
slots = ("event", "value", "exc", "owner", "done", "detached")
def __init__(self, owner: int) -> None:
self.event = threading.Event()
self.value: Optional[V] = None
self.exc: Optional[BaseException] = None
self.owner = owner
self.done = False
self.detached = False
class _Entry(Generic[V]):
slots = ("value", "expire_at")
def...
Mostrar resposta completa ▼
import threading
import time
from collections import OrderedDict
from typing import Callable, TypeVar, Generic, Hashable, Optional, Any
K = TypeVar("K", bound=Hashable)
V = TypeVar("V")
class _InFlight(Generic[V]):
slots = ("event", "value", "exc", "owner", "done", "detached")
def __init__(self, owner: int) -> None:
self.event = threading.Event()
self.value: Optional[V] = None
self.exc: Optional[BaseException] = None
self.owner = owner
self.done = False
self.detached = False
class _Entry(Generic[V]):
slots = ("value", "expire_at")
def __init__(self, value: V, expire_at: float) -> None:
self.value = value
self.expire_at = expire_at
class SingleFlightTTLCache(Generic[K, V]):
def init(
self,
capacity: int,
ttl: float,
clock: Callable[[], float] = time.monotonic,
) -> None:
if capacity < 0:
raise ValueError("capacity must be non-negative")
if ttl <= 0:
raise ValueError("ttl must be positive")
self._capacity = capacity
self._ttl = ttl
self._clock = clock
self._lock = threading.Lock()
self._store: "OrderedDict[K, _Entry[V]]" = OrderedDict()
self._inflight: dict[K, _InFlight[V]] = {}
# per-thread stack of keys currently being computed by this thread,
# used to detect same-thread recursion into an in-flight key.
self._thread_local = threading.local()
def _owned_keys(self) -> set:
stack = getattr(self._thread_local, "stack", None)
if stack is None:
stack = set()
self._thread_local.stack = stack
return stack
def _evict_if_needed(self) -> None:
while len(self._store) > self._capacity:
self._store.popitem(last=False)
def _purge_expired_locked(self) -> None:
now = self._clock()
expired_keys = [k for k, e in self._store.items() if now >= e.expire_at]
for k in expired_keys:
del self._store[k]
def get_or_compute(self, key: K, compute: Callable[[], V]) -> V:
owned = self._owned_keys()
while True:
with self._lock:
# Check completed, unexpired entry first.
entry = self._store.get(key)
if entry is not None:
if self._clock() >= entry.expire_at:
del self._store[key]
else:
self._store.move_to_end(key)
return entry.value
inflight = self._inflight.get(key)
if inflight is not None:
if inflight.owner == threading.get_ident() and key in owned:
raise RuntimeError(
"Detected same-thread recursive computation for key: "
f"{key!r}"
)
# Wait for existing computation outside the lock.
wait_target = inflight
else:
wait_target = None
my_flight = _InFlight(owner=threading.get_ident())
self._inflight[key] = my_flight
if wait_target is not None:
wait_target.event.wait()
if wait_target.exc is not None:
raise wait_target.exc
return wait_target.value # type: ignore[return-value]
# We own the computation for this key now.
owned.add(key)
try:
result = compute()
except BaseException as e:
with self._lock:
current = self._inflight.get(key)
if current is my_flight:
del self._inflight[key]
my_flight.exc = e
my_flight.done = True
my_flight.event.set()
raise
else:
with self._lock:
current = self._inflight.get(key)
still_current = current is my_flight
if still_current:
del self._inflight[key]
if still_current and not my_flight.detached:
expire_at = self._clock() + self._ttl
if self._capacity > 0:
self._store[key] = _Entry(result, expire_at)
self._store.move_to_end(key)
self._evict_if_needed()
# capacity == 0: never store
# If detached or superseded, do not store the result,
# but still release waiters below with the value.
my_flight.value = result
my_flight.done = True
my_flight.event.set()
return result
finally:
owned.discard(key)
def invalidate(self, key: K) -> None:
with self._lock:
if key in self._store:
del self._store[key]
inflight = self._inflight.get(key)
if inflight is not None:
inflight.detached = True
del self._inflight[key]
def clear(self) -> None:
with self._lock:
self._store.clear()
for inflight in self._inflight.values():
inflight.detached = True
self._inflight.clear()
def __len__(self) -> int:
with self._lock:
self._purge_expired_locked()
return len(self._store)
Resultado
Votos de vitória
3 / 3
Pontuação média
Pontuação total
Comentário geral
A resposta A é uma implementação em grande parte completa e executável. Ela usa corretamente um bloqueio global apenas para estado compartilhado, executa cálculos e esperas fora do bloqueio, compartilha trabalho em andamento, propaga falhas BaseException, suporta desanexação em invalidate/clear, lida com capacidade zero e implementa a ordenação LRU para acertos e inserções normais no cache. Sua principal fraqueza de correção é que a evicção de inserção não remove primeiro as entradas expiradas, de modo que entradas expiradas não-LRU podem causar evicção desnecessária de entradas ainda válidas. Há também pequenas questões de qualidade, como campos/importações não utilizados e uma guarda de recursão um tanto informal, mas o design é geralmente sólido.
Ver detalhes da avaliação ▼
Correção
Peso 35%Correto para a maioria dos comportamentos principais: single-flight thread-safe, cálculos independentes concorrentes, propagação de exceções incluindo BaseException, desanexação em invalidate/clear e compartilhamento de capacidade zero. A falha notável é a evicção sem remover primeiro as entradas expiradas, o que pode evictar entradas LRU válidas desnecessariamente quando entradas expiradas permanecem no armazenamento.
Completude
Peso 20%Implementa todos os métodos públicos solicitados e cobre quase todos os casos necessários, incluindo recuperação de falhas, expiração preguiçosa de __len__, atualizações de LRU e voos desanexados. Falta uma interação sutil, mas importante, entre a limpeza de expiração e a evicção de capacidade.
Qualidade do código
Peso 20%O modelo de estado é simples e compreensível, usando OrderedDict, um bloqueio, eventos e rastreamento de propriedade por thread. Alguns detalhes são grosseiros, como campos/importações não utilizados, valores de retorno de helper não tipados e nenhuma purga expirada antes da evicção, mas a estrutura é mantível.
Valor prático
Peso 15%Seria utilizável para muitas cargas de trabalho reais e lida com cenários de concorrência difíceis sem polling ou serialização de cálculos independentes. O bug de evicção de entrada expirada poderia causar perda surpreendente de entradas de cache válidas em uso de longa duração.
Seguimento de instruções
Peso 10%Segue a API solicitada, usa apenas a biblioteca padrão, retorna apenas código, inclui dicas de tipo, rejeita argumentos de construtor inválidos e visa a sintaxe compatível com Python 3.11.
Pontuação total
Comentário geral
A Resposta A fornece uma implementação excepcionalmente de alta qualidade, robusta e correta do complexo cache thread-safe. Demonstra uma profunda compreensão de primitivas de concorrência e condições de corrida. O código é bem estruturado, usa estruturas de dados apropriadas (como OrderedDict para LRU) e implementa corretamente todos os recursos especificados, incluindo os detalhes sutis de invalidação, detecção de recursão e tratamento de falhas. A estratégia de bloqueio é granular e correta, evitando manter o bloqueio global durante cálculos ou esperas de longa duração, o que é crucial para o desempenho.
Ver detalhes da avaliação ▼
Correção
Peso 35%A implementação é altamente correta e robusta. Lida corretamente com cenários complexos de concorrência, como corridas entre a conclusão do cálculo e a invalidação, verificando se o voo ainda está atual. O bloqueio é granular, liberando o bloqueio antes de esperar ou calcular. O tratamento de exceções e a detecção de recursão também são implementados corretamente.
Completude
Peso 20%A resposta está totalmente completa, implementando todos os recursos exigidos do prompt. Isso inclui a lógica principal `get_or_compute`, `invalidate`, `clear`, `__len__`, validação do construtor, despejo LRU, expiração TTL, single-flight, tratamento de falhas e os requisitos mais sutis como detecção de recursão na mesma thread e comportamento correto para capacidade zero.
Qualidade do código
Peso 20%A qualidade do código é excelente. É bem estruturado com classes auxiliares (`_InFlight`, `_Entry`) que modelam claramente o estado. Usa estruturas de dados apropriadas e eficientes (`OrderedDict` para operações LRU O(1)). O código é limpo, legível e inclui dicas de tipo adequadas.
Valor prático
Peso 15%Esta implementação tem alto valor prático. É um cache robusto, performático e completo em recursos que poderia ser usado diretamente em um ambiente de produção para resolver o problema de 'thundering herds'.
Seguimento de instruções
Peso 10%A resposta segue meticulosamente todas as instruções do prompt. Usa apenas a biblioteca padrão para Python 3.11, implementa a API exata solicitada e adere corretamente a todas as especificações comportamentais detalhadas em relação à concorrência, bloqueio, despejo e invalidação.
Pontuação total
Comentário geral
A Resposta A é uma solução quase completa e cuidadosamente elaborada. Utiliza um lock global apenas para transições de estado curtas, um Event por computação em andamento para que os esperadores bloqueiem sem reter o lock, um conjunto de chaves de propriedade por thread para detecção de recursão na mesma thread, e uma flag detached mais uma verificação de identidade (current is my_flight) para que computações detached ou substituídas nunca possam publicar sobre valores mais recentes. Compartilhamento com capacidade zero, propagação de exceções para BaseException incluindo KeyboardInterrupt/SystemExit, purga de expiração preguiçosa em len, LRU baseado em OrderedDict com descarte correto, e esperadores recebendo resultados mesmo quando a entrada é imediatamente descartada são todos tratados. Pequenas observações: re-lançar o mesmo objeto de exceção em múltiplos threads de esperadores pode compartilhar estado de traceback, esperadores não podem re-observar um valor em cache mais fresco se um aparecer enquanto eles esperam (aceitável por especificação), e a verificação do proprietário na detecção de recursão é ligeiramente redundante. No geral, é robusto, idiomático e corresponde de perto à especificação.
Ver detalhes da avaliação ▼
Correção
Peso 35%A expiração usa clock() >= expire_at conforme exigido, TTL é medido a partir da conclusão da computação, esperadores são liberados via Event tanto em sucesso quanto em qualquer BaseException, falhas não são cacheadas e retentativas funcionam, voos detached não podem sobrescrever valores mais recentes graças à verificação de identidade contra o registro em voo atual, recursão na mesma thread levanta RuntimeError, e nenhum lock é mantido durante a computação ou espera. Apenas pequenas questões permanecem, como re-lançar a mesma instância de exceção entre threads.
Completude
Peso 20%Todos os comportamentos especificados são implementados: validação do construtor, hits de LRU com move_to_end, single-flight por geração, compartilhamento de capacidade zero sem retenção, invalidação e limpeza com semântica de desprendimento adequada, expiração preguiçosa em __len__, descarte excluindo entradas em andamento, e esperadores recebendo resultados mesmo que imediatamente descartados. Nada da lista de requisitos está faltando.
Qualidade do código
Peso 20%Modelagem de estado limpa com helpers tipo dataclass __slots__, OrderedDict para LRU, conjunto local por thread para propriedade, separação clara do caminho de espera e do caminho do proprietário, type hints consistentes e comentários explicativos. Fluxo de controle ligeiramente denso em get_or_compute, mas bem organizado.
Valor prático
Peso 15%Diretamente utilizável em código concorrente real: sem busy-waiting, chaves independentes computam em paralelo, clock injetável permite testes determinísticos, e recuperação de falhas mantém o estado interno consistente mesmo sob KeyboardInterrupt ou SystemExit.
Seguimento de instruções
Peso 10%Retorna apenas código, usa apenas a biblioteca padrão, visa sintaxe compatível com Python 3.11, corresponde às assinaturas exatas do construtor e métodos, inclui type hints e evita polling conforme instruído.