简单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 来实现

#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]
时间: 2024-11-05 12:06:48

简单LRU cache 实现的相关文章

LRU Cache的简单实现

Cache这个东西可以说无处不在,处理器中的TLB,Linux系统中的高速页缓存,还有很多人熟知的开源软件memcached,都是cache的一种实现.LRU是Least Recently Used的缩写,即最近最少使用,是常用cache算法中的一种.因为cache的存储空间相对于后端存储来说更有限,将cache空间和后端存储空间映射后,还需要一些算法来解决cache满的问题并保证效率,LRU就是在cache满了以后,将最近最少访问到的内容移除,然后将新的内容放入cache,新的内容也成为了最近

LRU Cache (9)

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set. get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. set

[leetcode]LRU Cache (python)

LRU:最近最久未使用,为了得到这个最新最久的信息,需要一种策略来进行记录,如果加入类似时间戳式的字段,那么每次删除的时候,就必须通过遍历才能得到时间信息,或者对时间戳进行排序,但是无论哪种,都是需要额外的维护,维护成本都比较高. 广泛使用的策略是底层用双端队列来进行维护,双端使得在插入删除时操作更简单.而单单使用双端队列似乎还是不够,比如在get 时,还是需要顺序查找给定的key参数的,所以为了能在O(1) 时间获得key 需要类hash的结构,在python里,就用字典. 接下来的事情是,我

LeetCode——LRU Cache

Description: Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set. get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise r

[leedcode 146] LRU Cache

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set. get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.set(

【LeetCode 题解】 LRU Cache

设计并实现最近最久未使用(Least Recently Used)缓存. 链接:https://oj.leetcode.com/problems/lru-cache/ 题目描述: Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set. get(key) - Get the value (wi

Redis(八) LRU Cache

Redis(八)-- LRU Cache 在计算机中缓存可谓无所不在,无论还是应用还是操作系统中,为了性能都需要做缓存.然缓存必然与缓存算法息息相关,LRU就是其中之一.笔者在最先接触LRU是大学学习操作系统时的了解到的,至今已经非常模糊.在学习Redis时,又再次与其相遇,这里将这块内容好好梳理总结. LRU(Least Recently Used)是缓存算法家族的一员--最近最少使用算法,类似的算法还有FIFO(先进先出).LIFO(后进先出)等.因为缓存的选择一般都是用内存(RAM)或者计

146. LRU Cache

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put. get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. put

【Lintcode】LRU Cache, Data Stream Median

主要是priority_queue的用法 一个是内置类型优先队列怎么设置小根堆(默认大根堆) 如果是自定义数据结构,有两种办法 1.定义这种数据结构的比较符号,就可以当成内置类型整 2.传进去一个重载()的类,当小于号用,默认还是大根堆,也许传进去的是个callable object都行的吧,我试了一下函数好像不行,不懂,不管了 LRU Cache class LRUCache{ public: // @param capacity, an integer int Time; typedef i