This article mainly introduces a simple LRUcache implemented by Python. This article summarizes it based on actual needs. if you need it, you can refer to the cause: My colleagues need a fixed-size cache, if the record is in the cache, it is directly read from the cache; otherwise, it is read from the database. Python dict is a very simple cache, but because of the large data size, the memory is likely to grow too large, so you need to limit the number of records and use the LRU algorithm to discard old records. The key is an integer and the value is a python object of about 10 kB.
Analysis:
1) we can think of maintaining the key-> value relationship for the cache.
2) to implement LRU, we need a time-based priority queue to maintain the relationship between timestamp-> (key, value ).
3) when the number of records in the cache reaches maxsize, the minimum timestamp (key, value) must be output to the queue.
4) when a (key, value) is hit, we need to remove it from the queue and insert it to the end of the queue.
From the analysis, we can see that our cache needs to meet the above four functions to achieve optimal performance. for the rapid removal and insertion of Team tables, the linked list is obviously the best choice. in order to quickly remove, it is best to use a two-way linked list. to insert the tail, a pointer pointing to the tail is required.
The following is implemented using python:
The code is as follows:
# Encoding = UTF-8
Class LRUCache (object ):
Def _ init _ (self, maxsize ):
# Maximum number of cache records
Self. maxsize = maxsize
# For real data storage
Self. inner_dd = {}
# Linked list-head pointer
Self. head = None
# Linked list-tail pointer
Self. tail = None
Def set (self, key, value ):
# Reach 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, move the corresponding node to the end 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 ):
# You only need to process the situation in the queue header and in the middle
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]