起因:我的同事需要一个固定大小的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实现的一个简单LRU cache的更多相关文章

  1. python定义的一个简单的shell函数的代码

    把写代码过程中经常用到的一些代码段做个记录,如下代码段是关于python定义的一个简单的shell函数的代码. pipe = subprocess.Popen(cmd, stdout=subproce ...

  2. Windows 下针对python脚本做一个简单的进程保护

    前提: 大家运行的脚本程序经常会碰到系统异常关闭.或被其他用户错杀的情况.这样就需要一个进程保护的工具. 本文结合windows 的计划任务,实现一个简单的进程保护的功能. 利用py2exe生产 ex ...

  3. Python学习 - 编写一个简单的web框架(二)

    在上一篇日志中已经讨论和实现了根据url执行相应应用,在我阅读了bottle.py官方文档后,按照bottle的设计重写一遍,主要借鉴大牛们的设计思想. 一个bottle.py的简单实例 来看看bot ...

  4. python实现的一个简单的网页爬虫

    学习了下python,看了一个简单的网页爬虫:http://www.cnblogs.com/fnng/p/3576154.html 自己实现了一个简单的网页爬虫,获取豆瓣的最新电影信息. 爬虫主要是获 ...

  5. Flask学习之旅--用 Python + Flask 制作一个简单的验证码系统

    一.写在前面 现在无论大大小小的网站,基本上都会使用验证码,登录的时候要验证,下载的时候要验证,而使用的验证码也从那些简简单单的字符图形验证码“进化”成了需要进行图文识别的验证码.需要拖动滑块的滑动验 ...

  6. Python并发编程-一个简单的爬虫

    一个简单的爬虫 #网页状态码 #200 正常 #404 网页找不到 #502 504 import requests from multiprocessing import Pool def get( ...

  7. Python学习 - 编写一个简单的web框架(一)

    自己动手写一个web框架,因为我是菜鸟,对于python的一些内建函数不是清楚,所以在写这篇文章之前需要一些python和WSGI的预备知识,这是一系列文章.这一篇只实现了如何处理url. 参考这篇文 ...

  8. 使用Python来编写一个简单的感知机

    来表示.第二个元素是表示期望输出的值. 这个数组定义例如以下: training_data = [  (array([0,0,1]), 0),  (array([0,1,1]), 1),  (arra ...

  9. 利用python+tkinter做一个简单的智能电视遥控器

    要通过python实现遥控器功能分两步: 第一步:开发图形化界面,以暴风TV的遥控器按钮为例 第二步:使PC端给电视发送相应指令(此步骤需要打开电视的adb开关) 现在就开始第一步操作实现遥控器功能, ...

随机推荐

  1. 虚拟机centos 里tomcat的端口映射到主机 Windows里面

  2. @OneToMany

    实体关系之@OneToMany 博客分类: hibernate & ejb SQL  Order.java package com.entity; import java.io.Seriali ...

  3. Neo4j 第六篇:Cypher语法

    Cypher是图形数据库查询语言事实上的标准. 一,Cypher类型系统 Cypher支持的类型系统分为三类:属性类型,复合类型和结构类型. 1,属性类型 属性类型:Integer.Float.Str ...

  4. 2018 ICPC 徐州网络预赛 Features Track (STL map pair)

    [传送门]https://nanti.jisuanke.com/t/31458 [题目大意]有N个帧,每帧有K个动作特征,每个特征用一个向量表示(x,y).两个特征相同当且仅当他们在不同的帧中出现且向 ...

  5. 洛谷—— P2515 [HAOI2010]软件安装

    题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...

  6. 老系统优化同步导入10w+Excel数据 秒级

    背景:老系统asp.net 2.0项目使用客户反应,某个业务每个月导入数据操作很慢,大致需要15-30分钟才会导入完毕: 分析:导入慢的原因:  .数据量过大,且采用的是同步,单个excel shee ...

  7. 一道题目- Find the smallest range that includes at least one number from each of the k lists

    You have k lists of sorted integers. Find the smallest range that includes at least one number from ...

  8. fabricJs使用系列(一)

    Get the canvas object while using fabric js I'm using Fabric.js and I've created a fabric canvas obj ...

  9. C语言的代码内存布局具体解释

    一个程序本质上都是由 BSS 段.data段.text段三个组成的.这种概念在当前的计算机程序设计中是非常重要的一个基本概念,并且在嵌入式系统的设计中也非常重要,牵涉到嵌入式系统执行时的内存大小分配, ...

  10. vue2.0 常用的 UI 库

    1.mint-ui 安装: npm install mint-ui --save 使用: main.js // MintUI组件库 import MintUI from 'mint-ui' impor ...