当前位置: 首页 > 编程笔记 >

Python实现LRU算法的2种方法

姬温文
2023-03-14
本文向大家介绍Python实现LRU算法的2种方法,包括了Python实现LRU算法的2种方法的使用技巧和注意事项,需要的朋友参考一下

LRU:least recently used,最近最少使用算法。它的使用场景是:在有限的空间中存储对象时,当空间满时,会按一定的原则删除原有的对象,常用的原则(算法)有LRU,FIFO,LFU等。在计算机的Cache硬件,以及主存到虚拟内存的页面置换,还有Redis缓存系统中都用到了该算法。我在一次面试和一个笔试时,也遇到过这个问题。

LRU的算法是比较简单的,当对key进行访问时(一般有查询,更新,增加,在get()和set()两个方法中实现即可)时,将该key放到队列的最前端(或最后端)就行了,这样就实现了对key按其最后一次访问的时间降序(或升序)排列,当向空间中增加新对象时,如果空间满了,删除队尾(或队首)的对象。

在Python中,可以使用collections.OrderedDict很方便的实现LRU算法,当然,如果你想不到用OrderedDict,那可以用dict+list来实现。本文主要参考了LRU CACHE IN PYTHON,写的非常好,既实现了功能,又简洁易读。方法一的代码与参考文章基本相同,方法二是我自己想出来的,比较繁琐一些,其实OrderedDict本身也是类似的这种机制来实现的有序。

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

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

方法一:用OrderedDict实现(推荐)


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.has_key(key):             value = self.cache.pop(key)             self.cache[key] = value         else:             value = None                  return value     

    def set(self,key,value):         if self.cache.has_key(key):             value = self.cache.pop(key)             self.cache[key] = value         else:             if len(self.cache) == self.capacity:                 self.cache.popitem(last = False)    #pop出第一个item                 self.cache[key] = value             else:                 self.cache[key] = value


测试代码如下

c = LRUCache(5)

  

for i in range(5,10):

    c.set(i,10*i)

  

  

print c.cache, c.cache.keys()

  

c.get(5)

c.get(7)

  

print c.cache, c.cache.keys()

  

c.set(10,100)

print c.cache, c.cache.keys()

  

c.set(9,44)

print c.cache, c.cache.keys()

输出如下


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

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

OrderedDict([(8, 80), (9, 90), (5, 50), (7, 70), (10, 100)])   [8, 9, 5, 7, 10]

OrderedDict([(8, 80), (5, 50), (7, 70), (10, 100), (9, 90)])   [8, 5, 7, 10, 9]


方法二:用dict+list实现(不推荐)


class LRUCache(object):

    '''不能存储可变类型对象,不能并发访问set()'''

  

    def __init__(self,capacity):

        self.l = []

        self.d = {}

        self.capacity = capacity

         

    def get(self,key):         if self.d.has_key(key):             value = self.d[key]             self.l.remove(key)             self.l.insert(0,key)         else:             value = None                   return value      

    def set(self,key,value):         if self.d.has_key(key):             self.l.remove(key)         elif len(self.d) == self.capacity:                 oldest_key = self.l.pop()                 self.d.pop(oldest_key)                           self.d[key] = value         self.l.insert(0, key)


测试代码如下

c = LRUCache(5)

  

for i in range(5,10):

    c.set(i,10*i)

  

  

print c.d,c.l

  

c.get(5)

c.get(7)

  

print c.d,c.l

  

c.set(10,100)

print c.d,c.l

  

c.set(9,44)

print c.d,c.l

输出为


{8: 80, 9: 90, 5: 50, 6: 60, 7: 70}   [9, 8, 7, 6, 5]

{8: 80, 9: 90, 5: 50, 6: 60, 7: 70}   [7, 5, 9, 8, 6]

{5: 50, 7: 70, 8: 80, 9: 90, 10: 100} [10, 7, 5, 9, 8]

{5: 50, 7: 70, 8: 80, 9: 44, 10: 100} [9, 10, 7, 5, 8]

 类似资料:
  • 如果要成为一个有一定水平的程序员,算法是必须要会的。算法,让你的程序变得更有灵气。

  • 本文向大家介绍Django实现跨域的2种方法,包括了Django实现跨域的2种方法的使用技巧和注意事项,需要的朋友参考一下 jsonp 方式一:指定返回方法 方式二:不指定返回方法 cors 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。

  • 本文向大家介绍浅谈Python实现2种文件复制的方法,包括了浅谈Python实现2种文件复制的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例主要实现Python中的文件复制操作,有两种方法,具体实现代码如下所示: 总结 以上就是本文关于浅谈Python实现2种文件复制的方法的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站

  • 一、前言 上一章《Memcached源码分析 - Memcached源码分析之增删改查操作(5) 》中,我们讲到了SET命令的操作。当客户端向Memcached服务端SET一条缓存数据的时候,会将生成的Item地址挂到LRU的链表结构上。这一章节,我们主要讲一下Memcached是如何使用LRU算法的。 LRU:是Least Recently Used 近期最少使用算法。 二、Memcached的

  • 本文向大家介绍请你讲讲LRU算法的实现原理?相关面试题,主要包含被问及请你讲讲LRU算法的实现原理?时的应答技巧和注意事项,需要的朋友参考一下 考察点:LRU算法   ①LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也很高”,反过来说“如果数据最近这段时间一直都没有访问,那么将来被访问

  • 本文向大家介绍利用python实现汉字转拼音的2种方法,包括了利用python实现汉字转拼音的2种方法的使用技巧和注意事项,需要的朋友参考一下 前言 在浏览博客时,偶然看到了用python将汉字转为拼音的第三方包,但是在实现的过程中发现一些参数已经更新,现在将两种方法记录一下。 xpinyin 在一些博客中看到,如果要转化成带音节的拼音,需要传递参数,‘show_tone_marks=True',