Python实现的一个简单LRU cache


Posted in Python onSeptember 26, 2014

起因:我的同事需要一个固定大小的cache,如果记录在cache中,直接从cache中读取,否则从数据库中读取。python的dict 是一个非常简单的cache,但是由于数据量很大,内存很可能增长的过大,因此需要限定记录数,并用LRU算法丢弃旧记录。key 是整型,value是10KB左右的python对象

分析:

1)可以想到,在对于cache,我们需要维护 key -> value 的关系

2)而为了实现LRU,我们又需要一个基于时间的优先级队列,来维护   timestamp  -> (key, value) 的关系

3)当cache 中的记录数达到一个上界maxsize时,需要将timestamp 最小的(key,value) 出队列

4) 当一个(key, value) 被命中时,实际上我们需要将它从队列中,移除并插入到队列的尾部。

从分析可以看出我们的cache 要达到性能最优需要满足上面的四项功能,对于队表的快速移除和插入,链表显然是最优的选择,为了快速移除,最好使用双向链表,为了插入尾部,需要有指向尾部的指针。

下面用python 来实现:

#encoding=utf-8
class LRUCache(object):

    def __init__(self, maxsize):

        # cache 的最大记录数

        self.maxsize = maxsize

        # 用于真实的存储数据

        self.inner_dd = {}

        # 链表-头指针

        self.head = None

        # 链表-尾指针 

        self.tail = None
    def set(self, key, value):

        # 达到指定大小      

        if len(self.inner_dd) >= self.maxsize:

            self.remove_head_node()
        node = Node()

        node.data = (key, value)

        self.insert_to_tail(node)

        self.inner_dd[key] = node
    def insert_to_tail(self, node):

        if self.tail is None:

            self.tail = node

            self.head = node

        else:

            self.tail.next = node

            node.pre = self.tail

            self.tail = node
    def remove_head_node(self):

        node = self.head

        del self.inner_dd[node.data[0]]

        node = None

        self.head = self.head.next

        self.head.pre = None

    def get(self, key):

        if key in self.inner_dd:

            # 如果命中, 需要将对应的节点移动到队列的尾部

            node = self.inner_dd.get(key)

            self.move_to_tail(node)

            return node.data[1]

        return None
    def move_to_tail(self, node):

        # 只需处理在队列头部和中间的情况

        if not (node == self.tail):

            if node == self.head:

                self.head = node.next

                self.head.pre = None

                self.tail.next = node

                node.pre = self.tail

                node.next = None

                self.tail = node

            else:

                pre_node = node.pre

                next_node = node.next

                pre_node.next = next_node

                next_node.pre = pre_node
                self.tail.next = node

                node.pre = self.tail

                node.next = None

                self.tail = node
class Node(object):

    def __init__(self):

        self.pre = None

        self.next = None

        # (key, value)

        self.data = None
    def __eq__(self, other):

        if self.data[0] == other.data[0]:

            return True

        return False

    def __str__(self):

       return str(self.data)
if __name__ == '__main__':

    cache = LRUCache(10)

    for i in xrange(1000):

        cache.set(i, i+1)

        cache.get(2)

    for key in cache.inner_dd:

        print key, cache.inner_dd[key]
Python 相关文章推荐
Python中实现从目录中过滤出指定文件类型的文件
Feb 02 Python
pygame学习笔记(6):完成一个简单的游戏
Apr 15 Python
使用Python装饰器在Django框架下去除冗余代码的教程
Apr 16 Python
Python 实现一个颜色色值转换的小工具
Dec 06 Python
python抓取网页中链接的静态图片
Jan 29 Python
python pyenv多版本管理工具的使用
Dec 23 Python
使用tensorflow DataSet实现高效加载变长文本输入
Jan 20 Python
Python定时器线程池原理详解
Feb 26 Python
Windows+Anaconda3+PyTorch+PyCharm的安装教程图文详解
Apr 03 Python
Python学习之路之pycharm的第一个项目搭建过程
Jun 18 Python
python爬虫利器之requests库的用法(超全面的爬取网页案例)
Dec 17 Python
python用700行代码实现http客户端
Jan 14 Python
python网络编程实例简析
Sep 26 #Python
python的re模块应用实例
Sep 26 #Python
python实现自动登录人人网并访问最近来访者实例
Sep 26 #Python
编程语言Python的发展史
Sep 26 #Python
python人人网登录应用实例
Sep 26 #Python
python快速查找算法应用实例
Sep 26 #Python
python求众数问题实例
Sep 26 #Python
You might like
php获取当前时间的毫秒数的方法
2014/01/26 PHP
PHP使用DOMDocument类生成HTML实例(包含常见标签元素)
2014/06/25 PHP
yii2.0使用Plupload实现带缩放功能的多图上传
2015/12/22 PHP
替换php字符串中的单引号为双引号的方法
2017/02/16 PHP
利用php的ob缓存机制实现页面静态化方法
2017/07/09 PHP
js 内存释放问题
2010/04/25 Javascript
jQuery1.6 正式版发布并提供下载
2011/05/05 Javascript
利用javascript的面向对象的特性实现限制试用期
2011/08/04 Javascript
获取服务器传来的数据 用JS去空格的正则表达式
2012/03/26 Javascript
js特效,页面下雪的小例子
2013/06/17 Javascript
如何使用jQuery Draggable和Droppable实现拖拽功能
2013/07/05 Javascript
jquery $("#variable") 循环改变variable的值示例
2014/02/23 Javascript
轻松创建nodejs服务器(4):路由
2014/12/18 NodeJs
JavaScript使用Max函数返回两个数字中较大数的方法
2015/04/06 Javascript
深入分析javascript中console命令
2016/08/14 Javascript
JS中检测数据类型的几种方式及优缺点小结
2016/12/12 Javascript
vue如何使用 Slot 分发内容实例详解
2017/09/05 Javascript
JavaScript自执行函数和jQuery扩展方法详解
2017/10/27 jQuery
微信小程序canvas.drawImage完全显示图片问题的解决
2018/11/30 Javascript
详解使用React.memo()来优化函数组件的性能
2019/03/19 Javascript
Angular 多级路由实现登录页面跳转(小白教程)
2019/11/19 Javascript
Vue中axios拦截器如何单独配置token
2019/12/27 Javascript
详解ES6 扩展运算符的使用与注意事项
2020/11/12 Javascript
为什么推荐使用JSX开发Vue3
2020/12/28 Vue.js
Python入门篇之正则表达式
2014/10/20 Python
Python批量重命名同一文件夹下文件的方法
2015/05/25 Python
Python win32com 操作Exce的l简单方法(必看)
2017/05/25 Python
详解如何利用Cython为Python代码加速
2018/01/27 Python
Python3.6连接Oracle数据库的方法详解
2018/05/18 Python
OpenCV2从摄像头获取帧并写入视频文件的方法
2018/08/03 Python
Python多线程thread及模块使用实例
2020/04/28 Python
python基于socket函数实现端口扫描
2020/05/28 Python
CSS3模块的目前的状况分析
2010/02/24 HTML / CSS
HTML5 Canvas画线技巧——实现绘制一个像素宽的细线
2013/08/02 HTML / CSS
Melissa香港官网:MDreams
2016/07/01 全球购物
优质有机椰子产品:Dr. Goerg
2019/09/24 全球购物