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中的__new__()方法的使用
Apr 09 Python
Python内置函数——__import__ 的使用方法
Nov 24 Python
python2.7安装图文教程
Mar 13 Python
python基于物品协同过滤算法实现代码
May 31 Python
对python中数据集划分函数StratifiedShuffleSplit的使用详解
Dec 11 Python
对pyqt5多线程正确的开启姿势详解
Jun 14 Python
简单了解python关系(比较)运算符
Jul 08 Python
python实现基于朴素贝叶斯的垃圾分类算法
Jul 09 Python
python两个_多个字典合并相加的实例代码
Dec 26 Python
python Cartopy的基础使用详解
Nov 01 Python
详解Python遍历列表时删除元素的正确做法
Jan 07 Python
Python用tkinter实现自定义记事本的方法详解
Mar 31 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获取文件的MD5值并判断是否被修改的例子
2014/06/19 PHP
C/S和B/S两种架构区别与优缺点分析
2014/10/23 PHP
PHP版本常用的排序算法汇总
2015/12/20 PHP
[原创]IE view-source 无法查看看源码 JavaScript看网页源码
2009/07/19 Javascript
javascript实现页面内关键词高亮显示代码
2014/04/03 Javascript
JavaScript中对循环语句的优化技巧深入探讨
2014/06/06 Javascript
javascript背景时钟实现方法
2015/06/18 Javascript
AngularJS Phonecat实例讲解
2016/11/21 Javascript
jQuery实现鼠标滑过预览图片大图效果的方法
2017/04/26 jQuery
通俗解释JavaScript正则表达式快速记忆
2017/08/23 Javascript
vue项目部署到nginx/tomcat服务器的实现
2019/08/26 Javascript
layui加载数据显示loading加载完成loading消失的实例代码
2019/09/23 Javascript
vue视频播放插件vue-video-player的具体使用方法
2019/11/08 Javascript
vue-cli3.X快速创建项目的方法步骤
2019/11/14 Javascript
继承行为在 ES5 与 ES6 中的区别详解
2019/12/24 Javascript
Vue中的nextTick作用和几个简单的使用场景
2021/01/25 Vue.js
Python中使用ConfigParser解析ini配置文件实例
2014/08/30 Python
Python实现竖排打印传单手机号码易撕条
2015/03/16 Python
详解Python的Lambda函数与排序
2016/10/25 Python
Python二进制串转换为通用字符串的方法
2018/07/23 Python
python Flask 装饰器顺序问题解决
2018/08/08 Python
详解Python3 基本数据类型
2019/04/19 Python
基于python+selenium的二次封装的实现
2020/01/06 Python
基于Python爬虫采集天气网实时信息
2020/06/05 Python
H5 video poster属性设置视频封面的方法
2020/05/25 HTML / CSS
车库门开启器、遥控器和零件:Chamberlain
2019/04/09 全球购物
中国汽车租赁行业头部企业:一嗨租车
2019/05/16 全球购物
医学生个人求职信范文
2014/02/07 职场文书
内刊编辑求职自荐书范文
2014/02/19 职场文书
“四风”问题整改措施和努力方向
2014/09/20 职场文书
2015年爱牙日活动总结
2015/02/05 职场文书
灵魂歌王观后感
2015/06/17 职场文书
golang import自定义包方式
2021/04/29 Golang
一文搞懂Python Sklearn库使用
2021/08/23 Python
使用Bandicam录制鼠标指针并附带点击声音,还可以添加点击动画效果
2022/04/11 数码科技
python实现学生信息管理系统(面向对象)
2022/06/05 Python