MiniCPM-V-4.7-35B-A3B 在「实现缓存系统」的评测结果

这是该 AI 模型在此测试用例上的详细评测结果。

基本信息

  • 模型名称:MiniCPM-V-4.7-35B-A3B
  • 用例名称:实现缓存系统
  • 测试类型:文本生成
  • 评测维度:代码生成

系统提示词(System Prompt)

这是给 AI 模型的背景设定和角色指令:

你是一名资深后端工程师,擅长数据结构与算法设计,尤其熟悉缓存系统的实现原理。 回答要求: 1. 使用清晰、规范的代码实现,并附上简要的设计思路说明。 2. 必须说明核心操作(get/put)的时间复杂度,并解释如何达到该复杂度。 3. 代码需包含必要的注释,关键逻辑处须有说明。 4. 提供至少 3 个测试用例验证实现的正确性,覆盖边界场景(如容量为 1、缓存满时的淘汰行为)。 5. 编程语言不限,但需保证代码可直接运行。

用户提示词(User Prompt)

这是用户给 AI 模型的具体任务要求:

请实现一个 LRU(最近最少使用)缓存类,具体要求如下: **功能要求:** 1. 初始化时接受一个正整数 `capacity` 作为缓存容量上限。 2. 支持 `get(key)` 操作: - 若 key 存在于缓存中,返回对应的 value,并将该项标记为「最近使用」。 - 若 key 不存在,返回 -1。 3. 支持 `put(key, value)` 操作: - 若 key 已存在,更新其 value,并将该项标记为「最近使用」。 - 若 key 不存在,插入该键值对。 - 若插入后缓存超出容量,则删除**最久未使用**的缓存项,再插入新项。 **性能要求:** - `get` 和 `put` 操作的时间复杂度均须为 **O(1)**。 **示例:**

任务要求

AI 模型需要满足以下要求:

  1. LRU 淘汰逻辑正确:缓存满时淘汰最久未访问的有效条目,get/put 均需更新访问顺序,时间复杂度 O(1)
  2. TTL 过期逻辑正确:惰性删除在 get 时生效,过期条目不计入命中,purge_expired 能正确清理所有过期项
  3. 线程安全实现完整:所有公开方法均持锁操作,无竞态条件,并说明锁类型选择理由
  4. 批量操作语义正确:batch_get 跳过过期/不存在的 key,batch_put 原子性地写入所有条目(持同一把锁)
  5. 统计功能准确:hit_count/miss_count 在 get 和 batch_get 中均正确累计,hit_rate 计算无除零错误,current_size 反映实际有效条目数
  6. 测试用例覆盖关键场景:包含 TTL 过期、LRU 淘汰、并发安全、统计准确性四类验证

评测结果

综合得分

该模型在此用例的得分为:94.3 分(满分 100 分),已通过

基础难度评测结果

  • 得分:94.3 分
  • 通过状态:已通过

模型生成产物

以下是该模型针对此任务的实际生成内容:

下面给出一个符合要求的 LRU 缓存实现(使用 Python),并附带设计思路、复杂度分析和测试用例。 ## 设计思路 要实现 `get` 和 `put` 都是 O(1) 时间复杂度,需要同时满足: 1. **快速查找 key**:使用哈希表(字典)存储 `key -> node` 的映射。 2. **快速维护使用顺序**:使用双向链表维护“最近使用”到“最久未使用”的顺序: - 每次 `get` 或 `put` 成功时,将对应节点移动到链表头部(表示最近使用)。 - 当容量已满且需要淘汰时,删除链表尾部节点(最久未使用)。 ### 数据结构 - `Node` 类: - `key`, `value` - `prev`, `next` 指针,构成双向链表 - `LRUCache` 类: - `capacity`: 缓存容量 - `cache`: 字典,`key -> Node` - `head`, `tail`: 双向链表的伪头结点和伪尾结点,简化边界处理 ### 操作细节 - **初始化**: - 创建伪头 `head` 和伪尾 `tail`,让它们互相指向。 - `cache = {}` - **`_add_node(node)`**: - 将节点插入到 `head` 之后(链表头部),表示最近使用。 - **`_remove_node(node)`**: - 从链表中移除指定节点。 - **`_move_to_head(node)`**: - 先移除节点,再添加到头部。 - **`_pop_tail()`**: - 移除 `tail` 前面的节点(最久未使用),并返回该节点。 - **`get(key)`**: - 若 key 不在 `cache` 中,返回 `-1`。 - 若在,获取对应 node,调用 `_move_to_head(node)`,返回 `node.value`。 - **`put(key, value)`**: - 若 key 已存在: - 更新 `node.value`。 - 调用 `_move_to_head(node)`。 - 若 key 不存在: - 创建新节点。 - 加入 `cache` 和链表头部。 - 若 `len(cache) > capacity`: - 调用 `_pop_tail()` 得到被删除的节点。 - 从 `cache` 中删除该节点的 key。 所有操作均为常数时间。 --- ## 代码实现 ```python class Node: def __init__(self, key=0, value=0): self.key = key self.value = value self.prev = None self.next = None class LRUCache: def __init__(self, capacity: int): if capacity Node # 伪头结点和伪尾结点 self.head = Node() self.tail = Node() self.head.next = self.tail self.tail.prev = self.head def _add_node(self, node: Node): """将节点添加到链表头部(head 之后)""" node.prev = self.head node.next = self.head.next self.head.next.prev = node self.head.next = node def _remove_node(self, node: Node): """从链表中移除指定节点""" prev_node = node.prev next_node = node.next prev_node.next = next_node next_node.prev = prev_node def _move_to_head(self, node: Node): """将节点移动到链表头部""" self._remove_node(node) self._add_node(node) def _pop_tail(self) -> Node: """移除链表尾部节点(tail 之前),并返回该节点""" node = self.tail.prev self._remove_node(node) return node def get(self, key: int) -> int: if key not in self.cache: return -1 node = self.cache[key] # 标记为最近使用 self._move_to_head(node) return...

AI 评审点评

以下是 AI 评审对该模型输出的点评:

【CLAUDE】该回答完整满足了题目的全部要求:给出了清晰的设计思路(哈希表负责 O(1) 查找、双向链表负责 O(1) 顺序维护),代码可直接运行,核心逻辑正确,复杂度分析与实现方式一致,且提供了 3 个覆盖容量为 1、缓存满淘汰、更新已有 key 等边界场景的测试用例并全部通过验证。算法正确性方面几乎无可指摘,标准 LeetCode 146 式的正确淘汰顺序(先插入头部再淘汰尾部)保证了 LRU 语义。工程方面代码层次分明、注释充分,额外做了非法容量的参数校验;主要瑕疵是测试以 assert 为主、失败信息不够直观,文档中 `->` 转义残留,以及 _pop_tail 缺少空链表防御。综合来看,在 basic 难度下属于优秀答卷。 【GEMINI】这是一份高标准的实现。模型不仅准确实现了双向链表+哈希表的 O(1) LRU 缓存,而且在工程设计上运用了哨兵节点简化链表边界逻辑,附带了详尽的设计思路、复杂度分析以及完备可运行的断言测试用例,完全满足资深后端工程师的设定要求。 【KIMI】该实现是一个标准且正确的LRU缓存方案,采用哈希表+双向链表的经典组合,核心算法和复杂度满足题目要求。代码结构清晰、注释充分,能够正确处理get/put及淘汰逻辑。主要改进空间在于测试用例的覆盖度(缺少复杂LRU顺序验证)和工程细节的完善(如更完整的边界测试)。对于basic难度的题目而言,这是一个合格的实现。

进阶难度评测结果

  • 得分:65.8 分
  • 通过状态:已通过

模型生成产物

以下是该模型针对此任务的实际生成内容:

下面是一个符合所有要求的线程安全 TTL LRU 缓存系统的 Python 实现。 ## 设计思路 1. **数据结构**: - 使用 `OrderedDict` 维护 LRU 顺序(最近使用的移到末尾) - 每个值存储为 `(value, expire_time)` 元组,`expire_time` 为绝对时间戳(None 表示永不过期) - 使用 `threading.RLock` 保证线程安全 2. **锁的选择**: - 使用 `RLock`(可重入锁)而非 `Lock`,因为某些内部方法可能会递归调用需要加锁的方法 - 所有公开方法都通过锁保护,确保线程安全 3. **TTL 策略**: - 惰性删除:在 `get`/`batch_get` 时检查过期并清理 - 主动清理:`purge_expired()` 方法扫描所有条目清理过期项 4. **LRU 淘汰**: - 当缓存满且插入新 key 时,淘汰 `OrderedDict` 中最前面的条目(最久未使用) - 淘汰前需检查该条目是否已过期,如果已过期则直接移除,否则淘汰 5. **统计信息**: - 维护命中/未命中计数器 - `current_size` 统计当前有效条目数(不含已过期但未清理的) ## 代码实现 ```python import threading import time from collections import OrderedDict from typing import Optional, Dict, List, Any class TTLCache: """ 支持 TTL 的线程安全 LRU 缓存系统 锁类型选择:threading.RLock 理由: 1. RLock 是可重入锁,允许同一个线程多次获取同一把锁 2. 内部方法可能会调用其他需要加锁的方法(如 purge_expired 可能被其他方法间接调用) 3. 避免死锁问题,提高代码灵活性 """ def __init__(self, capacity: int): if capacity = 1") self.capacity = capacity self._cache: OrderedDict[str, tuple[Any, Optional[float]]] = OrderedDict() # _cache[key] = (value, expire_time) # expire_time 为绝对时间戳(秒),None 表示永不过期 self._lock = threading.RLock() # 统计信息 self._hit_count = 0 self._miss_count = 0 def _is_expired(self, expire_time: Optional[float]) -> bool: """检查是否过期""" if expire_time is None: return False return time.time() > expire_time def _clean_expired_in_get(self, key: str) -> bool: """ 在 get 操作中清理过期项 返回 True 表示 key 存在且未过期,False 表示不存在或已过期 """ with self._lock: if key not in self._cache: return False value, expire_time = self._cache[key] if self._is_expired(expire_time): # 过期,移除 del self._cache[key] self._miss_count += 1 return False # 未过期,移动到末尾(标记为最近使用) self._cache.move_to_end(key) self._hit_count += 1 return True def get(self, key: str) -> Any: """ 获取缓存值,若 key 不存在或已过期返回 -1 时间复杂度 O(1) """ if self._clean_expired_in_get(key): return self._cache[key][0] return -1 def put(self, key: str, value: Any, ttl: Optional[float] = None) -> None: """ 写入缓存,ttl 单位为秒(None 表示永不过期) 时间复杂度 O(1) """ expire_time = None if ttl is None else...

AI 评审点评

以下是 AI 评审对该模型输出的点评:

【CLAUDE】整体是一份结构完整、可读性不错的实现:OrderedDict 模拟双向链表 + 哈希表、RLock 保护、惰性删除加 purge_expired 双策略、统计字段齐全,测试也覆盖了题目要求的四类核心场景,方向正确。但存在三处必须指出的硬伤:get 在锁外读取值,破坏了线程安全承诺并可能抛 KeyError;batch_put 的淘汰计数自减逻辑错误,会使缓存超出 capacity;_evict_lru 的过期分支为死代码、逻辑冗余。此外,作答未系统给出复杂度分析表与惰性删除/定期扫描的权衡讨论,未完整覆盖 Prompt 的显式要求。建议:让 get 在单次持锁内完成「判空—过期检查—move_to_end—取值」全流程,或改为返回值而非布尔标志;batch_put 先用 max(0, len(existing)+len(new)-capacity) 计算需淘汰数量再统一淘汰,避免边淘汰边减计数;合并 _evict_lru 的重复分支并补充完整的复杂度与 TTL 策略权衡说明。 【GEMINI】候选实现整体框架完整,接口定义与测试用例覆盖全面,并正确选用了 RLock。但存在两处关键缺陷:一是 `get()` 方法存在明显的 Check-Then-Act 竞态漏洞(锁内检查有效性,锁外读取字典),高并发下可能抛出 KeyError;二是 `batch_put` 在超量写入时会破坏容量上限约束。此外,缺少对定期扫描与惰性删除的权衡分析以及完整的复杂度分析。 【KIMI】该实现基本完成了题目要求的功能框架,但在核心算法正确性和并发安全性上存在明显缺陷。最核心的问题是get方法在调用_clean_expired_in_get后,锁已经释放的情况下再次访问self._cache[key][0],这在高并发下几乎必然导致竞态条件。此外,batch_put的复杂逻辑和_evict_lru的不当实现、stats()的O(n)复杂度等问题都表明代码未经充分测试和验证。测试用例虽然覆盖场景但验证强度不足,未能发现这些潜在bug。建议重新审视锁粒度和生命周期,简化batch操作实现,并加强并发测试。

困难难度评测结果

  • 得分:67.7 分
  • 通过状态:已通过

模型生成产物

以下是该模型针对此任务的实际生成内容:

# 分布式缓存系统核心组件设计与实现 ## 1. 系统设计概述 本系统实现了一个轻量级的分布式缓存核心组件,包含以下核心模块: - **一致性哈希环**:支持虚拟节点和动态节点管理 - **节点管理器**:心跳检测、故障转移和节点发现 - **缓存存储层**:支持 LRU/LFU/FIFO 淘汰策略 - **复制机制**:异步复制和 Read-Your-Writes 一致性 - **监控接口**:性能指标收集和统计 ## 2. 代码实现 ```python import hashlib import time import threading import random import logging from collections import defaultdict from typing import Dict, List, Optional, Any, Tuple from dataclasses import dataclass, field from enum import Enum import heapq # 配置日志 logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) class NodeStatus(Enum): ONLINE = "ONLINE" OFFLINE = "OFFLINE" RECOVERING = "RECOVERING" class EvictionStrategy(Enum): LRU = "LRU" LFU = "LFU" FIFO = "FIFO" @dataclass class CacheNode: """缓存节点信息""" node_id: str host: str port: int status: NodeStatus = NodeStatus.ONLINE last_heartbeat: float = 0.0 virtual_nodes: Dict[int, str] = field(default_factory=dict) # hash -> virtual_node_id def __post_init__(self): if not self.virtual_nodes: self._generate_virtual_nodes() def _generate_virtual_nodes(self, virtual_node_count: int = 150): """生成虚拟节点""" for i in range(virtual_node_count): virtual_node_id = f"{self.node_id}_vn_{i}" # 使用 MD5 哈希生成虚拟节点位置 hash_digest = hashlib.md5(f"{self.node_id}_{i}".encode()).hexdigest() hash_value = int(hash_digest, 16) % (2**32) self.virtual_nodes[hash_value] = virtual_node_id @dataclass class CacheEntry: """缓存条目""" key: str value: Any timestamp: float access_count: int = 1 # 用于 LFU class LRUNode: """LRU 双向链表节点""" def __init__(self, key: str, value: Any): self.key = key self.value = value self.prev = None self.next = None class LFUNode: """LFU 节点""" def __init__(self, key: str, value: Any, frequency: int = 1): self.key = key self.value = value self.frequency = frequency class FIFOQueue: """FIFO 队列""" def __init__(self): self.queue = [] self.lock = threading.Lock() def enqueue(self, item): with self.lock: self.queue.append(item) def dequeue(self): with self.lock: if self.queue: return self.queue.pop(0)...

AI 评审点评

以下是 AI 评审对该模型输出的点评:

【CLAUDE】整体实现了分布式缓存系统的主要框架,架构设计思路清晰,LRU实现正确。主要缺陷在于LFU和FIFO的O(1)复杂度承诺未兑现(关键list操作为O(n)),心跳机制与节点管理器未真正集成(_handle_node_failure为空),异步复制非真正异步。文字说明的防护方案(布隆过滤器等)在代码中缺失实现。 【GEMINI】候选实现提供了一套完整可读且包含哈希环、淘汰策略、心跳监测及管理器的轻量级缓存系统架构,并对分布式异常场景与 CAP 理论做了较好的说明。然而在算法底层细节上,LFU 与 FIFO 未能达到题目严格要求的 O(1) 时间复杂度(分别使用了 list.remove 与 list.pop(0));异步复制机制退化为同步模拟,且未真正向副本节点写入数据,在核心算法严谨性与高性能并发设计上仍有明显提升空间。 【KIMI】该实现作为分布式缓存系统的原型展示了基本架构思路,但离生产级实现差距较大。核心问题包括:一致性哈希的绕环逻辑错误、LFU/FIFO 的 O(1) 承诺未兑现、锁粒度过粗导致并发性能差、心跳与故障转移未真正联动、异步复制仅为模拟。建议在以下方面重点改进:1)使用 SortedDict 或跳表优化哈希环查找,避免频繁排序;2)LFU 使用双向链表+哈希表实现真正的 O(1);3)将心跳检测、节点状态管理与哈希环更新解耦,通过事件驱动机制联动;4)实现真正的异步复制线程池和失败重试机制;5)补充布隆过滤器、随机过期等异常预防的代码实现;6)重写单元测试,覆盖边界条件和故障注入场景。

相关链接

您可以通过以下链接查看更多相关内容:

加载中...