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 08 Python
Java中重定向输出流实现用文件记录程序日志
Jun 12 Python
python增加矩阵维度的实例讲解
Apr 04 Python
python中ASCII码和字符的转换方法
Jul 09 Python
python爬虫 2019中国好声音评论爬取过程解析
Aug 26 Python
np.newaxis 实现为 numpy.ndarray(多维数组)增加一个轴
Nov 30 Python
如何基于python操作excel并获取内容
Dec 24 Python
解决windows上安装tensorflow时报错,“DLL load failed: 找不到指定的模块”的问题
May 20 Python
Python测试框架:pytest学习笔记
Oct 20 Python
python自动化之如何利用allure生成测试报告
May 02 Python
Python竟然能剪辑视频
May 25 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
Home Coffee Roasting
2021/03/03 咖啡文化
php xml-rpc远程调用
2008/12/19 PHP
一个比较简单的PHP 分页分组类
2009/12/10 PHP
PHP面向对象程序设计之类与反射API详解
2016/12/02 PHP
用javascript实现的支持lrc歌词的播放器
2007/05/17 Javascript
jQuery下通过$.browser来判断浏览器.
2011/04/05 Javascript
浅谈JavaScript函数参数的可修改性问题
2013/12/05 Javascript
z-blog SyntaxHighlighter 长代码无法换行解决办法(jquery)
2014/11/16 Javascript
AngularJS的一些基本样式初窥
2015/07/27 Javascript
javascript实现密码验证
2015/11/10 Javascript
vue的基本用法与常见指令
2017/08/15 Javascript
jquery实现淡入淡出轮播图效果
2020/12/13 jQuery
[01:11:46]DOTA2-DPC中国联赛 正赛 iG vs Magma BO3 第一场 2月23日
2021/03/11 DOTA
python抓取网页时字符集转换问题处理方案分享
2014/06/19 Python
介绍Python的Django框架中的QuerySets
2015/04/20 Python
Python实现购物程序思路及代码
2017/07/24 Python
Python 访问限制 private public的详细介绍
2018/10/16 Python
Django中的ajax请求
2018/10/19 Python
Python数据抓取爬虫代理防封IP方法
2018/12/23 Python
python+mysql实现学生信息查询系统
2019/02/21 Python
Python中一般处理中文的几种方法
2019/03/06 Python
Python OpenCV利用笔记本摄像头实现人脸检测
2020/08/20 Python
安装完Python包然后找不到模块的解决步骤
2020/02/13 Python
Python 实现RSA加解密文本文件
2020/12/30 Python
纽约现代艺术博物馆商店:MoMA STORE(室内家具和杂货商品)
2016/08/02 全球购物
C/C++程序员常见面试题二
2015/11/19 面试题
北京捷通华声语音技术有限公司Java软件工程师笔试题
2012/04/10 面试题
项目工作说明书
2014/07/29 职场文书
设备收款委托书范本
2014/10/02 职场文书
员工工作及收入证明
2014/10/28 职场文书
2015大学生实训报告
2014/11/05 职场文书
欢迎词范文
2015/01/27 职场文书
开展警示教育活动总结
2015/05/09 职场文书
2015年学校安全管理工作总结
2015/05/11 职场文书
多表查询、事务、DCL
2021/04/05 MySQL
一篇文章学会Vue中间件管道
2021/06/20 Vue.js