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实现的下载8000首儿歌的代码分享
Nov 21 Python
python中assert用法实例分析
Apr 30 Python
Django中传递参数到URLconf的视图函数中的方法
Jul 18 Python
Python读取视频的两种方法(imageio和cv2)
Apr 15 Python
Python实现绘制双柱状图并显示数值功能示例
Jun 23 Python
使用Python实现一个栈判断括号是否平衡
Aug 23 Python
在django admin中添加自定义视图的例子
Jul 26 Python
Python字符串、列表、元组、字典、集合的补充实例详解
Dec 20 Python
Python 余弦相似度与皮尔逊相关系数 计算实例
Dec 23 Python
jupyter 使用Pillow包显示图像时inline显示方式
Apr 24 Python
Python模块常用四种安装方式
Oct 20 Python
python使用XPath解析数据爬取起点小说网数据
Apr 22 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新手上路(十四)
2006/10/09 PHP
php中file_exists函数使用详解
2015/05/08 PHP
什么是PEAR?什么是PECL?PHP中两个容易混淆的概念解释
2015/07/01 PHP
基于命令行执行带参数的php脚本并取得参数的方法
2016/01/25 PHP
php判断是否连接上网络的方法实例详解
2016/12/14 PHP
php开发最强大的IDE编辑的phpstorm 2020.2配置Xdebug调试的详细教程
2020/08/17 PHP
Prototype1.6 JS 官方下载地址
2007/11/30 Javascript
JavaScript 基础篇之对象、数组使用介绍(三)
2012/04/07 Javascript
js拦截alert对话框另类应用
2013/01/16 Javascript
深入理解JavaScript 闭包究竟是什么
2013/04/12 Javascript
setTimeout()与setInterval()方法区别介绍
2013/12/24 Javascript
一个简单的Node.js异步操作管理器分享
2014/04/29 Javascript
老生常谈onBlur事件与onfocus事件(js)
2016/07/09 Javascript
jQuery EasyUI Tab 选项卡问题小结
2016/08/16 Javascript
使用jquery的jsonp如何发起跨域请求及其原理详解
2017/08/17 jQuery
vue 集成 vis-network 实现网络拓扑图的方法
2019/08/07 Javascript
layui监听select变化,以及设置radio选中的方法
2019/09/24 Javascript
json解析大全 双引号、键值对不在一起的情况
2019/12/06 Javascript
Vue 一键清空表单的实现方法
2020/02/07 Javascript
vant picker+popup 自定义三级联动案例
2020/11/04 Javascript
JavaScript代码实现微博批量取消关注功能
2021/02/05 Javascript
[02:07]2017国际邀请赛中国区预选赛直邀战队前瞻
2017/06/23 DOTA
Python编写百度贴吧的简单爬虫
2015/04/02 Python
Python字符串、元组、列表、字典互相转换的方法
2016/01/23 Python
Python父目录、子目录的相互调用方法
2019/02/16 Python
Python3.6中Twisted模块安装的问题与解决
2019/04/15 Python
Python命令行参数解析工具 docopt 安装和应用过程详解
2019/09/26 Python
python字典setdefault方法和get方法使用实例
2019/12/25 Python
pytorch ImageFolder的覆写实例
2020/02/20 Python
全球领先的各类汽车配件零售商:Advance Auto Parts
2016/08/26 全球购物
英语系本科生个人求职信
2013/09/21 职场文书
经典婚礼主持开场白
2014/03/13 职场文书
《欢乐的泼水节》教学反思
2014/04/22 职场文书
微笑服务演讲稿
2014/05/13 职场文书
资助贫困学生倡议书
2014/05/16 职场文书
赞美教师的句子
2019/09/02 职场文书