QSSS_new / backend /app /core /cache.py
misonL's picture
特性:实现对话框、表单、输入框、标签、下拉菜单、分隔线、骨架屏、滑块、表格、文本区域的 UI 组件
c78ce9e
Raw
History Blame Contribute Delete
4.71 kB
import collections
import sys
import threading
import logging
logger = logging.getLogger(__name__)
class LRUCache:
"""
基于LRU(最近最少使用)策略的内存缓存。
支持按条目数量和内存大小进行限制。
"""
def __init__(self, capacity: int = 100, max_memory_mb: int = 512):
"""
初始化LRU缓存。
:param capacity: 最大缓存条目数量。
:param max_memory_mb: 最大缓存内存限制(MB)。
"""
self.capacity = capacity
self.max_memory_bytes = max_memory_mb * 1024 * 1024 # 转换为字节
self.cache = collections.OrderedDict()
self.current_memory_bytes = 0
self.lock = threading.Lock()
logger.info(f"LRU缓存初始化:容量={capacity}条,最大内存={max_memory_mb}MB")
def _get_item_size(self, key, value):
"""
估算单个缓存条目(键值对)的内存大小(字节)。
注意:sys.getsizeof 不会递归计算对象大小,对于复杂对象可能不准确。
"""
return sys.getsizeof(key) + sys.getsizeof(value)
def get(self, key):
"""
从缓存中获取值。如果键存在,则将其标记为最近使用。
:param key: 缓存键。
:return: 对应的值,如果不存在则返回None。
"""
with self.lock:
if key not in self.cache:
return None
value = self.cache.pop(key)
self.cache[key] = value
logger.debug(f"从缓存获取: {key}")
return value
def set(self, key, value):
"""
将键值对存入缓存。如果缓存超出容量或内存限制,则移除最不常用的条目。
:param key: 缓存键。
:param value: 要缓存的值。
"""
with self.lock:
if key in self.cache:
old_value = self.cache.pop(key)
self.current_memory_bytes -= self._get_item_size(key, old_value)
item_size = self._get_item_size(key, value)
# 检查是否超出内存限制
while (
self.current_memory_bytes + item_size > self.max_memory_bytes
and len(self.cache) > 0
):
old_key, old_value = self.cache.popitem(last=False) # 移除最不常用的
self.current_memory_bytes -= self._get_item_size(old_key, old_value)
logger.warning(
f"缓存内存超出限制,移除最旧条目: {old_key},"
f"当前内存: {self.current_memory_bytes / (1024 * 1024):.2f}MB"
)
# 检查是否超出条目容量
while len(self.cache) >= self.capacity and len(self.cache) > 0:
old_key, old_value = self.cache.popitem(last=False) # 移除最不常用的
self.current_memory_bytes -= self._get_item_size(old_key, old_value)
logger.warning(f"缓存条目超出容量,移除最旧条目: {old_key},当前条目数: {len(self.cache)}")
self.cache[key] = value
self.current_memory_bytes += item_size
logger.debug(
f"设置缓存: {key},当前条目数: {len(self.cache)},"
f"当前内存: {self.current_memory_bytes / (1024 * 1024):.2f}MB"
)
def delete(self, key):
"""
从缓存中删除指定键。
:param key: 缓存键。
"""
with self.lock:
if key in self.cache:
value = self.cache.pop(key)
self.current_memory_bytes -= self._get_item_size(key, value)
logger.debug(f"从缓存删除: {key}")
def clear(self):
"""
清空缓存。
"""
with self.lock:
self.cache.clear()
self.current_memory_bytes = 0
logger.info("缓存已清空。")
def __len__(self):
"""
返回缓存中的条目数量。
"""
with self.lock:
return len(self.cache)
def get_current_memory_usage_mb(self) -> float:
"""
获取当前缓存占用的内存大小(MB)。
"""
with self.lock:
return self.current_memory_bytes / (1024 * 1024)
# 全局缓存实例,将在config中配置其容量和内存限制
cache_instance = None
def get_cache_instance(capacity: int = 100, max_memory_mb: int = 512):
"""
获取LRU缓存的单例实例。
"""
global cache_instance
if cache_instance is None:
cache_instance = LRUCache(capacity, max_memory_mb)
return cache_instance