起因:我的同事需要一个固定大小的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. Codeforces 837D Round Subset(背包)

    题目链接  Round Subset 题意  在n个数中选择k个数,求这k个数乘积末尾0个数的最大值. 首先我们预处理出每个数5的因子个数c[i]和2的因子个数d[i] 然后就可以背包了. 设f[i] ...

  2. Codeforces 451 E Devu and Flowers

    Discription Devu wants to decorate his garden with flowers. He has purchased n boxes, where the i-th ...

  3. 一起学习CMake – 01

    一起学习CMake – 01 本节介绍CMake里最常用的三个命令,分别是cmake_minimum_required; project; add_executable等. CMake是个好东西,在使 ...

  4. 【转】C语言中整型运算取Ceiling问题

    原文:http://blog.csdn.net/laciqs/article/details/6662472 --------------------------------------------- ...

  5. cocos2d-x-3.6 引擎概述

    cocos2d-x是一个游戏开发引擎,从公布到如今也有五六年了,一路看它慢慢壮大.它是如今应用最多的开源2d引擎,没有之中的一个,据说已经占据90%的市场,所以.对于想从事游戏开发的童鞋来说还是有必要 ...

  6. shell 检查文件夹所属用户组

    shell 检查文件夹所属用户组 #!/bin/bash # 检查文件夹 权限是否777 检查文件夹所属组是否www # authro ranmufei # 2017 08 21 云板容器版 /dat ...

  7. fetch 函数分装

    1.fetch /** * 封装 fetch */ import { hashHistory } from 'react-router'; export default function reques ...

  8. Android命令行下蓝牙使用

    注意:此部分仅仅适用于broadcom 系列蓝牙芯片,比如RK903, AP6xxx 系列 通过su 命令切换到root 用户 1.先确认RFKILL 驱动已经载入 ls /sys/class/rfk ...

  9. Codeforces 486E LIS of Sequence(线段树+LIS)

    题目链接:Codeforces 486E LIS of Sequence 题目大意:给定一个数组.如今要确定每一个位置上的数属于哪一种类型. 解题思路:先求出每一个位置选的情况下的最长LIS,由于開始 ...

  10. 鼠标滚轮实现图片的缩放-------Day79

    今天是7月的最后一天了,不得不说,我定下的七月份剩余几天的计划是完不成了.一则工作确实紧了些,再则没能处理好生活.工作和学习的节奏.这才是人生最大的课题吧.只是也还好.至少自己还在坚持着.事实上真的越 ...