Python实现的一个简单LRU cache
起因:我的同事需要一个固定大小的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 来实现:
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的更多相关文章
- python定义的一个简单的shell函数的代码
把写代码过程中经常用到的一些代码段做个记录,如下代码段是关于python定义的一个简单的shell函数的代码. pipe = subprocess.Popen(cmd, stdout=subproce ...
- Windows 下针对python脚本做一个简单的进程保护
前提: 大家运行的脚本程序经常会碰到系统异常关闭.或被其他用户错杀的情况.这样就需要一个进程保护的工具. 本文结合windows 的计划任务,实现一个简单的进程保护的功能. 利用py2exe生产 ex ...
- Python学习 - 编写一个简单的web框架(二)
在上一篇日志中已经讨论和实现了根据url执行相应应用,在我阅读了bottle.py官方文档后,按照bottle的设计重写一遍,主要借鉴大牛们的设计思想. 一个bottle.py的简单实例 来看看bot ...
- python实现的一个简单的网页爬虫
学习了下python,看了一个简单的网页爬虫:http://www.cnblogs.com/fnng/p/3576154.html 自己实现了一个简单的网页爬虫,获取豆瓣的最新电影信息. 爬虫主要是获 ...
- Flask学习之旅--用 Python + Flask 制作一个简单的验证码系统
一.写在前面 现在无论大大小小的网站,基本上都会使用验证码,登录的时候要验证,下载的时候要验证,而使用的验证码也从那些简简单单的字符图形验证码“进化”成了需要进行图文识别的验证码.需要拖动滑块的滑动验 ...
- Python并发编程-一个简单的爬虫
一个简单的爬虫 #网页状态码 #200 正常 #404 网页找不到 #502 504 import requests from multiprocessing import Pool def get( ...
- Python学习 - 编写一个简单的web框架(一)
自己动手写一个web框架,因为我是菜鸟,对于python的一些内建函数不是清楚,所以在写这篇文章之前需要一些python和WSGI的预备知识,这是一系列文章.这一篇只实现了如何处理url. 参考这篇文 ...
- 使用Python来编写一个简单的感知机
来表示.第二个元素是表示期望输出的值. 这个数组定义例如以下: training_data = [ (array([0,0,1]), 0), (array([0,1,1]), 1), (arra ...
- 利用python+tkinter做一个简单的智能电视遥控器
要通过python实现遥控器功能分两步: 第一步:开发图形化界面,以暴风TV的遥控器按钮为例 第二步:使PC端给电视发送相应指令(此步骤需要打开电视的adb开关) 现在就开始第一步操作实现遥控器功能, ...
随机推荐
- 2017-10-29-morning-清北模拟赛
T1 遭遇 #include <algorithm> #include <cstdio> #include <cmath> inline void read(int ...
- 服务器Out of Memory
之前有次把图片存储在数据库,结果读取时候报错了:Out of Memory.. 图片本来不应该存储在数据库中的,消耗内存太大,既然已经这样,那就先解决问题,不改存储方式. 如果一个应用程序为了提高性能 ...
- idea tomcat 配置
昨天我们讲了如何新建多模块项目:idea创建maven多模块项目 本节课,我们讲如何配置tomcat,使昨天配置的web项目,JRapid.Admin可以运行起来.具体步骤如下 第一步 第二步 第三步 ...
- django : related_name and related_query_name
This post is about two Django ForeignKey parameters related_name related_query_name See an example b ...
- BUPT 2012复试机考 1T
题目描述 大家都知道,数据在计算机里中存储是以二进制的形式存储的. 有一天,小明学了C语言之后,他想知道一个类型为unsigned int 类型的数字,存储在计算机中的二进制串是什么样子的. 你能帮帮 ...
- ZT:150条毒鸡汤
1.照照镜子吧,还要什么段子? 2.多年过去,再回忆高考,其实本质上没有考到好与坏的说法,重要的是年轻人在一起,做份试题,然后决定去哪座城市做代购. 3.真正努力过的人,就会明白天赋的重要性. 4.转 ...
- insertion-sort-list——链表、插入排序、链表插入
Sort a linked list using insertion sort. PS:需要考虑left为head且只有一个数时,此时left->==NULL,若right<left则应更 ...
- shell学习五十六天----延迟进程调度
延迟进程调度 前言:大部分时候,我们都希望进程快点開始,开点结束,别卡.而shell的运行,也是在前一个命令后,立即接着运行下一个命令.命令完毕的速度是与资源的限制有关,且不在shell的权限下. 在 ...
- Leetcode(58)题解:Length of Last Word
https://leetcode.com/problems/length-of-last-word/ 题目: Given a string s consists of upper/lower-case ...
- Struts%$#区别
1.#符号的用途一般有三种.1)访问非根对象属性,例如示例中的#session.msg表达式,由于Struts 2中值栈被视为根对象,所以访问其他非根对象时,需要加#前缀.实际上,#相当于Action ...