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中文件I/O高效操作处理的技巧分享
Feb 04 Python
Php多进程实现代码
May 07 Python
tensorflow 获取模型所有参数总和数量的方法
Jun 14 Python
python将txt等文件中的数据读为numpy数组的方法
Dec 22 Python
Python Datetime模块和Calendar模块用法实例分析
Apr 15 Python
Python日志无延迟实时写入的示例
Jul 11 Python
Django CBV类的用法详解
Jul 26 Python
django-crontab实现服务端的定时任务的示例代码
Feb 17 Python
Python实现屏幕录制功能的代码
Mar 02 Python
sqlalchemy实现时间列自动更新教程
Sep 02 Python
Windows环境下Python3.6.8 importError: DLLload failed:找不到指定的模块
Nov 01 Python
5道关于python基础 while循环练习题
Nov 27 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 地址栏信息的获取代码
2009/01/07 PHP
php中serialize序列化与json性能测试的示例分析
2013/04/27 PHP
PHP导航下拉菜单的实现如此简单
2013/09/22 PHP
php保存信息到当前Session的方法
2015/03/16 PHP
PHP中字符与字节的区别及字符串与字节转换示例
2016/10/15 PHP
PHP输出图像imagegif、imagejpeg与imagepng函数用法分析
2016/11/14 PHP
Javascript根据指定下标或对象删除数组元素
2012/12/21 Javascript
JS实现可改变列宽的table实例
2013/07/02 Javascript
JS仿iGoogle自定义首页模块拖拽特效的方法
2015/02/13 Javascript
深入理解$.each和$(selector).each
2016/05/15 Javascript
jQuery插件Validation快速完成表单验证的方式
2016/07/28 Javascript
JS禁止查看网页源代码的实现方法
2016/10/12 Javascript
基于JavaScript实现前端文件的断点续传
2016/10/17 Javascript
微信小程序 教程之wxapp视图容器 scroll-view
2016/10/19 Javascript
jQuery日程管理插件fullcalendar使用详解
2017/01/07 Javascript
更强大的vue ssr实现预取数据的方式
2019/07/19 Javascript
vue pages 多入口项目 + chainWebpack 全局引用缩写说明
2020/09/21 Javascript
Python生成随机数的方法
2014/01/14 Python
网站渗透常用Python小脚本查询同ip网站
2017/05/08 Python
Python 查找字符在字符串中的位置实例
2018/05/02 Python
python3.5 email实现发送邮件功能
2018/05/22 Python
Python实现批量修改图片格式和大小的方法【opencv库与PIL库】
2018/12/03 Python
django使用LDAP验证的方法示例
2018/12/10 Python
python变量命名的7条建议
2019/07/04 Python
python join方法使用详解
2019/07/30 Python
Python如何基于smtplib发不同格式的邮件
2019/12/30 Python
美国珠宝网上商店:Jeulia
2016/09/01 全球购物
西班牙香水和化妆品购物网站:Arenal Perfumerías
2019/03/01 全球购物
Ray-Ban雷朋瑞典官方网站:全球领先的太阳眼镜品牌
2019/08/22 全球购物
Ever New美国:澳大利亚领先的女装时尚品牌
2019/11/28 全球购物
大学生就业推荐信范文
2013/11/29 职场文书
综治维稳工作汇报
2014/10/27 职场文书
公司感谢信范文
2015/01/22 职场文书
金砖之国观后感
2015/06/11 职场文书
用Python爬取某乎手机APP数据
2021/06/15 Python
Python快速实现一键抠图功能的全过程
2021/06/29 Python