首先,lru是一个cache,使用方式是:
lru cache(1024)
lru.get(key)
lru.put(key,value)
当我们说线程安全的时候,指有一个全局变量lru cache, 多个线程都能读写,要并发访问控制;
实现方式也比较简单,就是给lru这个类添加一个lock属性就可以了。
下面是一个使用 Python 实现的 线程安全的 LRU Cache(最近最少使用缓存) ,采用:
- 自定义双向链表 + 字典(dict) :用于快速访问和维护访问顺序。
- threading.Lock:保证在多线程环境下操作的安全性。
✅ 功能要求
- 支持
get(key)和put(key, value)操作。 - 当容量满时,自动删除最久未使用的条目(LRU 策略)。
- 支持并发访问(线程安全)。
🧱 核心结构说明
-
双向链表节点类(
Node) :- 存储 key、value
- 有
prev和next指针
-
LRUCache 类:
- 使用字典
self.cache快速定位节点 - 维护一个双向链表来记录使用顺序
- 头部是最新的节点,尾部是最久未使用的节点
- 使用
self.lock = threading.Lock()来保护共享资源
- 使用字典
✅ Python 实现代码如下:
python
深色版本
import threading
class Node:
def __init__(self, key=None, value=None):
self.key = key
self.value = value
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.cache = {} # key -> Node
self.size = 0
# 初始化双向链表的虚拟头尾节点
self.head = Node()
self.tail = Node()
self.head.next = self.tail
self.tail.prev = self.head
self.lock = threading.Lock() # 线程锁
def _add_node(self, node):
"""将节点添加到头部"""
node.prev = self.head
node.next = self.head.next
self.head.next.prev = node
self.head.next = node
def _remove_node(self, 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):
"""将节点移动到头部"""
self._remove_node(node)
self._add_node(node)
def get(self, key):
with self.lock:
if key not in self.cache:
return -1
node = self.cache[key]
self._move_to_head(node) # 最近访问了,移到头部
return node.value
def put(self, key, value):
with self.lock:
if key in self.cache:
node = self.cache[key]
node.value = value
self._move_to_head(node)
return
if self.size >= self.capacity:
# 删除尾部节点(最久未使用)
tail_prev = self.tail.prev
self._remove_node(tail_prev)
del self.cache[tail_prev.key]
self.size -= 1
new_node = Node(key, value)
self._add_node(new_node)
self.cache[key] = new_node
self.size += 1
📦 使用示例
python
深色版本
# 示例:单线程测试
lru = LRUCache(2)
lru.put(1, 10)
lru.put(2, 20)
print(lru.get(1)) # 输出: 10
lru.put(3, 30) # 容量已满,会淘汰 key=2
print(lru.get(2)) # 输出: -1 (已被淘汰)
# 示例:多线程测试
def worker(cache):
for i in range(100):
cache.put(i, i * 10)
print(cache.get(i))
import threading
cache = LRUCache(10)
threads = [threading.Thread(target=worker, args=(cache,)) for _ in range(4)]
for t in threads:
t.start()
for t in threads:
t.join()
🔒 线程安全性说明
- 所有对
cache,head,tail,size的访问都包裹在with self.lock:中。 - 这样可以防止多个线程同时修改数据结构导致的状态不一致或竞态条件。
🚀 性能优化建议(进阶)
如果你追求极致性能,还可以:
- 将
Node替换为namedtuple或者用__slots__提升内存效率。 - 使用更细粒度的锁(如分段锁),适用于高并发场景。
- 替换为
OrderedDict(Python 3.7 前常用实现方式)。
如果你需要基于 OrderedDict 或者 functools.lru_cache 的版本,也可以告诉我,我可以继续补充。