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编程过程中用单元测试法调试代码的介绍
Apr 02 Python
Python利用Nagios增加微信报警通知的功能
Feb 18 Python
详解Swift中属性的声明与作用
Jun 30 Python
python中defaultdict的用法详解
Jun 07 Python
Django中login_required装饰器的深入介绍
Nov 24 Python
利用Python对文件夹下图片数据进行批量改名的代码实例
Feb 21 Python
Python二进制文件读取并转换为浮点数详解
Jun 25 Python
Python3.7黑帽编程之病毒篇(基础篇)
Feb 04 Python
Python定时从Mysql提取数据存入Redis的实现
May 03 Python
Python logging模块原理解析及应用
Aug 13 Python
python实现股票历史数据可视化分析案例
Jun 10 Python
Python sklearn分类决策树方法详解
Sep 23 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
简单介绍下 PHP5 中引入的 MYSQLI的用途
2007/03/19 PHP
php中heredoc与nowdoc介绍
2014/12/25 PHP
ThinkPHP在Cli模式下使用模板引擎的方法
2015/09/25 PHP
php简单实现sql防注入的方法
2016/04/22 PHP
PHP CURL采集百度搜寻结果图片不显示问题的解决方法
2017/02/03 PHP
PHP如何通过表单直接提交大文件详解
2019/01/08 PHP
JavaScript RegExp方法获取地址栏参数(面向对象)
2009/03/10 Javascript
JavaScript 变量命名规则
2009/09/23 Javascript
40款非常有用的 jQuery 插件推荐(系列一)
2011/12/21 Javascript
JS中令人发指的valueOf方法介绍
2013/02/22 Javascript
jquery及原生js获取select下拉框选中的值示例
2013/10/25 Javascript
JavaScript中的this关键字使用方法总结
2015/03/13 Javascript
jQuery插件slider实现拖动滑块选取价格范围
2015/04/30 Javascript
javascript中for/in循环及使用技巧
2015/09/01 Javascript
jQuery实现手机版页面翻页效果的简单实例
2016/10/05 Javascript
js仿小米手机上下滑动效果
2017/02/05 Javascript
浅析 NodeJs 的几种文件路径
2017/06/07 NodeJs
axios+Vue实现上传文件显示进度功能
2019/04/14 Javascript
微信小程序 子级页面返回父级并把子级参数带回父级实现方法
2019/08/22 Javascript
5个你不知道的JavaScript字符串处理库(小结)
2020/06/01 Javascript
如何检测JavaScript中的死循环示例详解
2020/08/30 Javascript
vue+iview实现文件上传
2020/11/17 Vue.js
vue3使用vue-count-to组件的实现
2020/12/25 Vue.js
Python3实现生成随机密码的方法
2014/08/23 Python
Python使用遗传算法解决最大流问题
2018/01/29 Python
python单例模式获取IP代理的方法详解
2018/09/13 Python
Python3多线程版TCP端口扫描器
2019/08/31 Python
在django中自定义字段Field详解
2019/12/03 Python
Html5 FileReader实现即时上传图片功能实例代码
2014/09/01 HTML / CSS
Topman美国官网:英国著名的国际平价时尚男装品牌
2017/12/22 全球购物
企业新年寄语
2014/04/04 职场文书
毕业设计说明书
2014/05/07 职场文书
股东授权委托书范本
2014/09/13 职场文书
家属答谢词
2015/01/05 职场文书
二审答辩状格式
2015/05/22 职场文书
java设计模式--原型模式详解
2021/07/21 Java/Android