在Python中实现 LRU 缓存装饰器
LRU 是缓存替换算法,它删除最近最少使用的数据并存储新数据。假设我们有一个 10 个内存帧的缓存空间。并且每一帧都填充了一个文件。现在,如果我们要存储新文件,我们需要删除缓存中最旧的文件并添加新文件。这就是 LRU 的工作原理。
LRU 缓存由 Queue 和 Dictionary 数据结构组成。
- 队列:存储最近使用到最近最少使用的文件
- 哈希表:用于存储文件及其在缓存中的位置
Refer to the below articles to get more information about the topic:
- Python and LRU Cache
- LRU cache implementation
什么是装饰器?
装饰器是一个函数,它接受一个函数作为它的唯一参数并返回一个函数。这有助于一遍又一遍地用相同的代码“包装”功能。
注意:有关更多信息,请参阅Python中的装饰器。
现在,在了解了Python中 LRU 和装饰器的基本概念之后,我们来看看 LRU 缓存装饰器在Python中的实现。
Python3
from collections import deque
# LRU cache implementation
class LRUCache:
def __init__(self, size=5):
self.size = size
self.container = deque()
self.map = dict()
def reallocate(self):
# to reallocate the hashmap for
# every access of file access file
# will reallocate the data in hashmap
# according to the numbers position
# in the container for every access,
# hit and miss(evict)
if len(self.container) > 1:
for key, val in enumerate(self.container):
self.map[val] = key
def access(self, val):
# print("access "+str(val))
self.container.remove(val)
self.container.appendleft(val)
self.reallocate()
def evict(self, val):
# print("cache miss "+str(val))
if val in self.map:
#del self.map[val]
self.container.remove(val)
else:
x = self.container.pop()
del self.map[x]
self.normal_insert(val)
def normal_insert(self, val):
self.container.appendleft(val)
self.reallocate()
def insert(self, val):
if val in self.map.keys():
# if value in present in
# the hashmap then it is a hit.
# access function will access the
# number already present and replace
# it to leftmost position
self.access(val)
else:
# if value is not present in
# the hashtable
if (len(self.map.keys()) == self.size):
# if the size of the queue
# is equal to capacity and
# we try to insert the number,
# then it is a miss then,
# evict function will delete the
# right most elements and insert
# the latest element in the
# leftmost position
self.evict(val)
else:
# normal_insert function will normally
# insert the data into the cache..
self.normal_insert(val)
def print(self):
lru_elements = [x for x in self.container]
print(lru_elements)
# definition of lru decorator
def LRUDecorator(size):
lru = LRUCache(size)
def decorator(function):
def functionality(num):
lru.insert(num)
lru.print()
# to check the num pageframe(position)
# uncomment the below statement
# print(lur.map)
print(num, function(num))
return functionality
return decorator
# Using LRU Decorator
@LRUDecorator(size=4)
def ex_func_01(n):
print(f'Computing...{n}')
time.sleep(1)
return n
print(f'\nFunction: ex_func_01')
print(ex_func_01(1))
print(ex_func_01(2))
print(ex_func_01(3))
print(ex_func_01(4))
print(ex_func_01(1))
print(ex_func_01(2))
print(ex_func_01(5))
print(ex_func_01(1))
print(ex_func_01(2))
print(ex_func_01(3))
print(ex_func_01(4))
print(ex_func_01(5))
输出:
Function: ex_func_01
[1]
Computing...1
1 1
None
[2, 1]
Computing...2
2 2
None
[3, 2, 1]
Computing...3
3 3
None
[4, 3, 2, 1]
Computing...4
4 4
None
[1, 4, 3, 2]
Computing...1
1 1
None
[2, 1, 4, 3]
Computing...2
2 2
None
[5, 2, 1, 4]
Computing...5
5 5
None
[1, 5, 2, 4]
Computing...1
1 1
None
[2, 1, 5, 4]
Computing...2
2 2
None
[3, 2, 1, 5]
Computing...3
3 3
None
[4, 3, 2, 1]
Computing...4
4 4
None
[5, 4, 3, 2]
Computing...5
5 5
None