Cause: My colleague needs a fixed-size cache that will be read from the database if it is recorded in the cache and read directly from the cache. Python's dict is a very simple cache, but because of the large amount of data, the memory is likely to grow too large, so you need to limit the number of records and discard the old records with the LRU algorithm. Key is integer, value is a Python object about 10KB
Analysis:
1) It can be thought that, in the case of the cache, we need to maintain the relationship of key-value
2) and in order to implement LRU, we need a time-based priority queue to maintain the relationship of timestamp (key, value)
3) When the number of records in the cache reaches an upper bound of maxsize, the timestamp minimum (key,value) is required to be out of the queue
4) When a (key, value) is hit, we actually need to remove it from the queue and insert it into the tail of the queue.
From the analysis we can see that our cache to achieve optimal performance needs to meet the above four functions, for the quick removal and insertion of the team table, the list is obviously the best choice, in order to quickly remove, it is best to use a doubly linked list, in order to insert the tail, you need to have a pointer to the tail.
The following is implemented in Python:
Copy the Code code as follows:
#encoding =utf-8
Class LRUCache (object):
def __init__ (self, maxsize):
# cache Maximum number of records
Self.maxsize = MaxSize
# for real-world storage data
SELF.INNER_DD = {}
# linked List-head pointer
Self.head = None
# linked List-tail pointer
Self.tail = None
def set (self, key, value):
# reaches the specified size
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:
# if hit, the corresponding node needs to be moved to the tail of the queue
node = self.inner_dd.get (key)
Self.move_to_tail (node)
return node.data[1]
Return None
def move_to_tail (Self, node):
# just handle the situation in the head and middle of the queue
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]