Respuesta 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 respuesta 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 ganadores
3 / 3
Puntuación media
Puntuación total
Comentario general
La respuesta A es una implementación mayormente completa y ejecutable. Utiliza correctamente un bloqueo global solo para el estado compartido, ejecuta cálculos y esperas fuera del bloqueo, comparte el trabajo en curso, propaga fallos de BaseException, admite la desconexión en invalidate/clear, maneja la capacidad cero e implementa el orden LRU para aciertos y inserciones normales en la caché. Su principal debilidad de corrección es que la evacuación de inserciones no purga primero las entradas caducadas, por lo que las entradas caducadas no LRU pueden causar la evacuación innecesaria de entradas aún válidas. También hay problemas de calidad menores, como campos/importaciones no utilizados y una protección de recursión algo informal, pero el diseño es generalmente sólido.
Ver detalle de evaluación ▼
Corrección
Peso 35%Correcto para la mayoría de los comportamientos principales: single-flight seguro para hilos, cálculos independientes concurrentes, propagación de excepciones incluida BaseException, desconexión en invalidate/clear y compartición de capacidad cero. El defecto notable es la evacuación sin eliminar primero las entradas caducadas, lo que puede evacuar entradas LRU válidas innecesariamente cuando quedan entradas caducadas en el almacén.
Integridad
Peso 20%Implementa todos los métodos públicos solicitados y cubre casi todos los casos requeridos, incluida la recuperación de fallos, la expiración perezosa de __len__, las actualizaciones LRU y los vuelos desconectados. Omite una interacción sutil pero importante entre la limpieza de expiración y la evacuación de capacidad.
Calidad del código
Peso 20%El modelo de estado es simple y comprensible, utilizando OrderedDict, un bloqueo, eventos y seguimiento de propiedad por hilo. Algunos detalles son toscos, como campos/importaciones no utilizados, valores de retorno de ayudantes sin tipo y sin purga de caducados antes de la evacuación, pero la estructura es mantenible.
Valor práctico
Peso 15%Sería utilizable para muchas cargas de trabajo reales y maneja escenarios de concurrencia difíciles sin sondeo ni serialización de cálculos independientes. El error de evacuación de entradas caducadas podría causar una pérdida sorprendente de entradas de caché válidas en usos prolongados.
Seguimiento de instrucciones
Peso 10%Sigue la API solicitada, utiliza solo la biblioteca estándar, devuelve solo código, incluye sugerencias de tipo, rechaza argumentos de constructor no válidos y tiene como objetivo la sintaxis compatible con Python 3.11.
Puntuación total
Comentario general
La respuesta A proporciona una implementación excepcionalmente de alta calidad, robusta y correcta de la compleja caché segura para hilos. Demuestra una profunda comprensión de los primitivos de concurrencia y las condiciones de carrera. El código está bien estructurado, utiliza estructuras de datos apropiadas (como OrderedDict para LRU) e implementa correctamente todas las características especificadas, incluidos los detalles sutiles de invalidación, detección de recursión y manejo de fallos. La estrategia de bloqueo es granular y correcta, evitando mantener el bloqueo global durante cálculos o esperas de larga duración, lo cual es fundamental para el rendimiento.
Ver detalle de evaluación ▼
Corrección
Peso 35%La implementación es altamente correcta y robusta. Maneja correctamente escenarios de concurrencia complejos, como carreras entre la finalización del cálculo y la invalidación, comprobando si el vuelo sigue siendo actual. El bloqueo es granular, liberando el bloqueo antes de esperar o calcular. El manejo de excepciones y la detección de recursión también se implementan correctamente.
Integridad
Peso 20%La respuesta está completamente completa, implementando todas las características requeridas de la indicación. Esto incluye la lógica principal `get_or_compute`, `invalidate`, `clear`, `__len__`, validación del constructor, desalojo LRU, expiración TTL, single-flight, manejo de fallos y los requisitos más sutiles como la detección de recursión en el mismo hilo y el comportamiento correcto para capacidad cero.
Calidad del código
Peso 20%La calidad del código es excelente. Está bien estructurado con clases auxiliares (`_InFlight`, `_Entry`) que modelan claramente el estado. Utiliza estructuras de datos apropiadas y eficientes (`OrderedDict` para operaciones LRU O(1)). El código es limpio, legible e incluye anotaciones de tipo adecuadas.
Valor práctico
Peso 15%Esta implementación tiene un alto valor práctico. Es una caché robusta, de alto rendimiento y completa en características que podría usarse directamente en un entorno de producción para resolver el problema de las manadas de truenos.
Seguimiento de instrucciones
Peso 10%La respuesta sigue meticulosamente todas las instrucciones de la indicación. Utiliza solo la biblioteca estándar para Python 3.11, implementa la API exacta solicitada y se adhiere correctamente a todas las especificaciones de comportamiento detalladas con respecto a la concurrencia, el bloqueo, el desalojo y la invalidación.
Puntuación total
Comentario general
La respuesta A es una solución casi completa y cuidadosamente diseñada. Utiliza un bloqueo global solo para transiciones de estado cortas, un Event por cálculo en curso para que los esperadores bloqueen sin mantener el bloqueo, un conjunto de claves propias por hilo para la detección de recursión en el mismo hilo, y una bandera detached más una verificación de identidad (current is my_flight) para que los cálculos detached o reemplazados nunca puedan publicar valores más nuevos. Se manejan el uso compartido de capacidad cero, la propagación de excepciones para BaseException, incluida KeyboardInterrupt/SystemExit, la purga perezosa de expiración en len, LRU basado en OrderedDict con evacuación correcta, y los esperadores que reciben resultados incluso cuando la entrada se evacua inmediatamente. Pequeños detalles: volver a lanzar la misma excepción en múltiples hilos de espera puede compartir el estado del traceback, los esperadores no pueden volver a observar un valor en caché más fresco si aparece uno mientras esperan (aceptable según la especificación), y la verificación del propietario en la detección de recursión es ligeramente redundante. En general, es robusto, idiomático y se ajusta estrechamente a la especificación.
Ver detalle de evaluación ▼
Corrección
Peso 35%La expiración utiliza clock() >= expire_at según lo requerido, el TTL se mide desde la finalización del cálculo, los esperadores se liberan a través de Event tanto en caso de éxito como en cualquier BaseException, las fallas no se almacenan en caché y las reintentos funcionan, los vuelos desvinculados no pueden sobrescribir valores más nuevos gracias a la verificación de identidad contra el registro en curso actual, la recursión en el mismo hilo genera RuntimeError, y no se mantiene ningún bloqueo durante el cálculo o la espera. Solo quedan problemas menores, como volver a lanzar la misma instancia de excepción entre hilos.
Integridad
Peso 20%Se implementan todos los comportamientos especificados: validación del constructor, aciertos de LRU con move_to_end, single-flight por generación, uso compartido de capacidad cero sin retención, invalidación y limpieza con semántica de desvinculación adecuada, expiración perezosa en __len__, evacuación excluyendo entradas en curso, y esperadores que reciben resultados incluso si se evacuan inmediatamente. No falta nada de la lista de requisitos.
Calidad del código
Peso 20%Modelado de estado limpio con ayudantes tipo dataclass __slots__, OrderedDict para LRU, conjunto local por hilo para la propiedad, separación clara de la ruta de espera y la ruta del propietario, sugerencias de tipo consistentes y comentarios explicativos. Flujo de control ligeramente denso en get_or_compute pero bien organizado.
Valor práctico
Peso 15%Directamente utilizable en código concurrente real: sin espera activa, claves independientes se calculan en paralelo, el reloj inyectable permite pruebas deterministas, y la recuperación de fallos mantiene el estado interno consistente incluso bajo KeyboardInterrupt o SystemExit.
Seguimiento de instrucciones
Peso 10%Devuelve solo código, utiliza solo la biblioteca estándar, apunta a sintaxis compatible con Python 3.11, coincide con las firmas exactas del constructor y los métodos, incluye sugerencias de tipo y evita el sondeo según las instrucciones.