Resposta A: Google Gemini 2.5 Flash-Lite
Resposta: ```python import threading import time from collections import OrderedDict class Node: def __init__(self, key, value): self.key = key self.value = value self.prev = None self.next = None class LRUCache: def __init__(self, capacity: int): if capacity <= 0: raise ValueError("A capacidade deve ser um inteiro positivo.") self.capacity = capacity self.cache = {} self.head = Node(None, None) # Cabeça fictícia self.tail = Node(None, None) # Cauda fictícia self.head.next = self.tail self.tail.prev = s...
Mostrar resposta completa ▼
Resposta: ```python import threading import time from collections import OrderedDict class Node: def __init__(self, key, value): self.key = key self.value = value self.prev = None self.next = None class LRUCache: def __init__(self, capacity: int): if capacity <= 0: raise ValueError("A capacidade deve ser um inteiro positivo.") self.capacity = capacity self.cache = {} self.head = Node(None, None) # Cabeça fictícia self.tail = Node(None, None) # Cauda fictícia self.head.next = self.tail self.tail.prev = self.head self.lock = threading.RLock() # Usando RLock para simplificar neste exemplo, mas uma abordagem mais granular é possível. def _remove_node(self, node): prev_node = node.prev next_node = node.next prev_node.next = next_node next_node.prev = prev_node def _add_to_front(self, node): node.next = self.head.next node.prev = self.head self.head.next.prev = node self.head.next = node def get(self, key): with self.lock: if key in self.cache: node = self.cache[key] self._remove_node(node) self._add_to_front(node) return node.value return None def put(self, key, value): with self.lock: if key in self.cache: node = self.cache[key] node.value = value self._remove_node(node) self._add_to_front(node) else: if len(self.cache) >= self.capacity: # Remover item LRU lru_node = self.tail.prev self._remove_node(lru_node) del self.cache[lru_node.key] new_node = Node(key, value) self.cache[key] = new_node self._add_to_front(new_node) def delete(self, key): with self.lock: if key in self.cache: node = self.cache[key] self._remove_node(node) del self.cache[key] return True return False def __len__(self): with self.lock: return len(self.cache) def __str__(self): with self.lock: items = [] current = self.head.next while current != self.tail: items.append(f"({current.key}: {current.value})") current = current.next return " -> ".join(items) # --- Explicação da Estratégia de Concorrência --- # Esta implementação usa um único threading.RLock para todas as operações (get, put, delete). # Embora isso garanta segurança para threads, não minimiza a contenção como solicitado pelo prompt. # Uma abordagem mais avançada e granular envolveria segmentar o cache ou usar # estruturas de dados sem bloqueio. Por exemplo, seria possível usar múltiplos locks, cada um protegendo um subconjunto # das entradas do cache (striped locking), ou usar locks de leitura-escrita para permitir que múltiplos leitores # acessem diferentes partes do cache simultaneamente. # O RLock atual garante que apenas uma thread possa modificar o estado interno do cache (o dicionário e a lista duplamente encadeada) por vez. # Isso evita condições de corrida em que múltiplas threads poderiam tentar atualizar o mesmo nó, adicionar/remover nós ou desalojar entradas simultaneamente, levando à corrupção de dados ou a uma ordenação LRU incorreta. # O uso de RLock (Reentrant Lock) permite que uma thread adquira o lock múltiplas vezes, o que pode ser útil em cenários complexos, mas não muda fundamentalmente as características de contenção em comparação com um Lock padrão neste uso específico. # --- Demonstração --- def worker(cache, operations, thread_id): for op, key, value in operations: if op == 'get': cache.get(key) elif op == 'put': cache.put(key, value) elif op == 'delete': cache.delete(key) # Simular algum trabalho e permitir que outras threads sejam executadas time.sleep(0.001) def run_demonstration(): print("Executando Demonstração do Cache LRU...") capacity = 5 cache = LRUCache(capacity) num_threads = 10 ops_per_thread = 50 all_operations = [] for i in range(num_threads): thread_ops = [] for j in range(ops_per_thread): op_type = ['get', 'put', 'delete'][j % 3] key = (i * ops_per_thread + j) % (capacity * 2) # Chaves que podem ou não estar no cache value = f"val_{i}_{j}" thread_ops.append((op_type, key, value)) all_operations.append(thread_ops) threads = [] for i in range(num_threads): thread = threading.Thread(target=worker, args=(cache, all_operations[i], i)) threads.append(thread) thread.start() for thread in threads: thread.join() print(f"Demonstração concluída. Tamanho final do cache: {len(cache)}") # Garantir que o cache nunca exceda sua capacidade assert len(cache) <= capacity, f"Capacidade do cache excedida! Tamanho atual: {len(cache)}, Capacidade: {capacity}" print("Asserção aprovada: a capacidade do cache é mantida.") # Verificação básica de integridade dos dados (não exaustiva) print("Realizando verificação básica de integridade...") # Esta é uma verificação muito básica. Um teste mais robusto envolveria rastrear os estados esperados. # Por enquanto, apenas garantimos que não haja corrupção óbvia, como tamanho negativo ou exceções durante o acesso. try: # Tentar acessar algumas chaves que provavelmente foram inseridas for i in range(min(5, capacity)): key_to_check = (i * ops_per_thread) % (capacity * 2) cache.get(key_to_check) print("Verificação básica de integridade aprovada.") except Exception as e: print(f"A verificação de integridade falhou com a exceção: {e}") assert False, "A verificação de integridade do cache falhou." if __name__ == "__main__": run_demonstration() ```
Resultado
Votos de vitoria
0 / 3
Pontuacao media
Pontuacao total
Comentario geral
A resposta A implementa um cache LRU convencional com um dicionário mais lista duplamente ligada e sua lógica LRU single-threaded básica é sólida. Ela lida corretamente com a validação de capacidade positiva, get/put/delete, e inclui uma demonstração multithreaded. No entanto, ela usa explicitamente um RLock global em cada operação, o que viola o requisito da solicitação de evitar um lock de grão grosso e não permite gets concorrentes em chaves diferentes. As asserções da demonstração são fracas e não validam significativamente a correção de concorrência estrita ou a integridade dos dados além das verificações básicas de capacidade.
Ver detalhes da avaliacao ▼
Correcao
Peso 35%A implementação de dicionário mais lista duplamente ligada está correta para o comportamento LRU padrão, e o get atualiza a recência enquanto o put remove o tail.prev. O comportamento de delete também está correto. No entanto, a correção para o cenário concorrente pretendido é limitada pela serialização completa sob um único lock, e o design não aborda as condições de corrida mais difíceis que a tarefa enfatiza.
Completude
Peso 20%Inclui a API necessária, validação para capacidade não positiva, explicação e uma demonstração multithreaded. Mas não atende à solicitação de minimizar a contenção ou leituras concorrentes não bloqueantes em chaves diferentes, e a demonstração não testa profundamente a correção sob interleavings.
Qualidade do codigo
Peso 20%O código é legível, direto e organizado de forma clara. Os métodos auxiliares para operações de lista são sensatos. No entanto, há uma importação desnecessária de OrderedDict, a explicação admite que o design não é o que foi solicitado, e a lógica de teste é bastante superficial.
Valor pratico
Peso 15%Como um cache LRU simples thread-safe, é utilizável na prática, mas o único lock global cria alta contenção e frustra o principal requisito prático para acesso concorrente escalável. A demonstração dá pouca confiança para cargas de trabalho multithreaded reais.
Seguimento de instrucoes
Peso 10%Segue os requisitos de API e formato de módulo, mas claramente não atende à instrução de evitar um lock global de grão grosso e permitir gets concorrentes em chaves diferentes. Essa é uma falha importante no requisito central.
Pontuacao total
Comentario geral
A Resposta A fornece uma implementação correta de cache LRU com estrutura adequada de lista duplamente ligada e mapa hash, lógica de despejo correta e tratamento apropriado de casos extremos. O código é limpo e legível. No entanto, falha fundamentalmente no requisito central de concorrência ao usar um único RLock para todas as operações, o que o próprio autor reconhece como inaceitável de acordo com o prompt. A demonstração está presente, mas as asserções são mínimas. Esta é uma implementação base sólida que precisaria de um redesenho significativo para atender aos requisitos de concorrência de granularidade fina.
Ver detalhes da avaliacao ▼
Correcao
Peso 35%A Resposta A implementa um cache LRU correto com lista duplamente ligada e mapa hash adequados. A lógica de despejo, as operações get/put/delete e o tratamento de casos extremos (ValueError para capacidade não positiva) estão todos corretos. No entanto, usa um único RLock para tudo, o que o próprio autor reconhece não satisfazer o requisito de concorrência de granularidade fina. A semântica LRU está correta, mas o modelo de concorrência é ingênuo.
Completude
Peso 20%A Resposta A inclui todas as operações necessárias, tratamento de casos extremos e uma demonstração com vários threads. No entanto, falha explicitamente em implementar a concorrência de granularidade fina exigida (usa um único RLock global), que é um requisito central. A demonstração está presente, mas as asserções são mínimas e a verificação de integridade é superficial.
Qualidade do codigo
Peso 20%A Resposta A é limpa e legível, com boa estrutura. O uso de sentinelas de cabeça/cauda fictícias é apropriado. No entanto, usar RLock em vez de Lock é desnecessário aqui e o comentário reconhece que a implementação não atende aos requisitos declarados. O código está bem organizado, mas o design de concorrência é uma deficiência conhecida.
Valor pratico
Peso 15%A abordagem de bloqueio único da Resposta A tem valor prático limitado para cenários de alta concorrência. Funcionaria corretamente, mas seria um gargalo sob carga. O autor reconhece essa limitação. Para uso em produção, a implementação precisaria de um redesenho significativo.
Seguimento de instrucoes
Peso 10%A Resposta A segue a maioria das instruções, mas falha explicitamente no requisito central de ir além de um único bloqueio global. O prompt afirma que 'um único bloqueio de grão grosso em tudo não é aceitável' e a Resposta A usa exatamente isso. O autor reconhece isso nos comentários, o que demonstra consciência, mas não resolve o problema. A demonstração e o tratamento de casos extremos estão presentes.
Pontuacao total
Comentario geral
A Resposta A fornece uma implementação correta e thread-safe de um cache LRU usando um dicionário padrão e uma lista duplamente ligada. O seu código é limpo e fácil de entender. No entanto, falha fundamentalmente no requisito central de concorrência da solicitação ao usar um único lock global para todas as operações. Embora reconheça corretamente essa limitação na sua explicação, essa escolha de design torna-a uma solução não-conforme e muito mais simples do que o solicitado. O código de demonstração é funcional, mas as suas verificações de integridade são muito básicas.
Ver detalhes da avaliacao ▼
Correcao
Peso 35%A lógica LRU e a thread-safety estão corretas devido ao único lock global. No entanto, não é uma implementação correta do design *concorrente* solicitado, pois serializa todas as operações, falhando em atingir o objetivo de desempenho.
Completude
Peso 20%A resposta fornece todos os componentes solicitados: a implementação da classe, uma explicação e uma demonstração. No entanto, a implementação principal está incompleta em relação aos requisitos de concorrência da solicitação.
Qualidade do codigo
Peso 20%O código é limpo, bem comentado e segue os idiomatismos padrão do Python. A implementação do dicionário e da lista duplamente ligada é direta e correta.
Valor pratico
Peso 15%Um cache LRU com um único lock tem valor prático limitado em aplicações de alta concorrência, pois o lock rapidamente se torna um gargalo. Serve como um exemplo básico de livro didático, mas não é uma solução de alto desempenho.
Seguimento de instrucoes
Peso 10%A resposta falha em seguir uma restrição negativa chave na solicitação: "um único lock de grão grosso em tudo não é aceitável." Ao usar um único RLock para todas as operações, viola diretamente esta instrução, que era central para a dificuldade da tarefa.