Cause: My colleague needs a fixed-size cache. If the record is in the cache, it will be read directly from the cache; otherwise, it will be 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.
# Encoding = utf-8class lrucache (object): def _ init _ (self, maxsize): # maximum number of cache records self. maxsize = maxsize # used to store real data self. inner_dd ={}# linked list-header pointer self. head = none # linked list-tail pointer 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. 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. 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. pre = self. tail node. next = none self. tail = nodeclass 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]
Simple LRU cache implementation