LRU算法--python实现

最近最少使用算法LRU(Least Recently Used)

原理:

按照使用时间倒排序,然后从尾部删除元素。

场景:

  • 在有限的空间中,存储对象时,当空间满时,会按一定的原则删除原有的对象,
    常用的原则(算法)LRU, FIFO, LFU等。

  • 计算机的Cache硬件,以及主存到虚拟内存的页面置换,Redis缓存系统。

LRU算法比较简单,当对key进行访问时,将该key放置到队列的最前端(或者最后端),这样
实现了对key按最后一次访问的时间降序(或升序)排列,当向空间增加新对象时,如果空间
满了,删除队尾(或队首)对象。

python中使用collections.OrderedDict很方便实现LRU算法。

下面的实现是有问题的,这个cache的key:value键值对中,value只能是不可变类型。因为,如果value是可变类型,那对于同一个key,所有调用get(key)方法返回的value都是指向同一个可变对象的,当修改其中一个value时,那所有的value都会被修改了,即使你没有调用set()方法也会这样。这是我们不希望看到的。解决方法我想到了两种,一是可变对象序列化后再存储,即将可变对象转为不可变对象;二是仍存储可变对象,但get()时,返回一个深拷贝,这样每个get()调用返回的对象就不会相互影响了。推荐第一种方法。另外,对于key,推荐使用str/unicode类型。

当并发时,还会存在一个问题,因为这涉及到对公共资源的写操作,所以必须要对set()加锁。其实,在并发情况下,所有对公共资源的写操作都要加锁。如果不存在并发的情况,只有单线程,那可以不加锁。

"""
implement the LRU(leasted Recently Used)
"""
# -*- coding: utf-8 -*-

from collections import OrderedDict


class LRUCache(OrderedDict):
    """
    不能存储可变类型对象,不能并发访问set()
    """
    def __init__(self, capacity):
        self.capacity = capacity
        self.cache = OrderedDict()
        
    def get(self, key):
        if self.cache.__contains__(key):
            value = self.cache.pop(key)
            self.cache[key] = value
        else:
            value = None
        
        return value
    
    def set(self, key, value):
        if self.cache.__contains__(key):
            value = self.cache.pop(key)
            self.cache[key] = value
        else:
            if len(self.cache) == self.capacity:
                self.cache.popitem(last=False)
                self.cache[key] = value
            else:
                self.cache[key] = value
                
if __name__ == '__main__':
    c = LRUCache(5)
    for i in range(5, 10):
        c.set(i, 10*i)
    print(f"{c.cache, c.cache.keys()}")
    c.get(5)
    c.get(7)
    print(f"{c.cache, c.cache.keys()}")

结果:
(OrderedDict([(5, 50), (6, 60), (7, 70), (8, 80), (9, 90)]), odict_keys([5, 6, 7, 8, 9]))
(OrderedDict([(6, 60), (8, 80), (9, 90), (5, 50), (7, 70)]), odict_keys([6, 8, 9, 5, 7]))

posted @ 2022-03-24 18:45  酷酷的排球  阅读(383)  评论(0编辑  收藏  举报