『码农翻身』高速缓存置换策略
计算机高速缓存
- 字:是指存放在一个存储单元中的二进制代码的组合
- 字块:存储在连续的存储单元中而被看作是一个单元的一组字
高速缓存由多个字块组成
高速缓存的替换策略
先进先出算法(FIFO)
- 把高速缓存看作是一个先进先出的队列
- 优先替换最先进入队列的字块
最不经常使用算法(LFU)
- 优先淘汰最不经常使用的字块
- 需要额外的空间记录字块的使用频率
最近最少使用算法(LRU)
- 优先淘汰一段时间内没有使用的字块
- 有多种实现方法,一般使用双向链表
页面置换算法的实现
双向链表
from typing import Any, Union
class Node(object):
def __init__(self, key: Any, value: Any):
self.key: Any = key
self.value: Any = value
self.prev: Node = None
self.next: Node = None
def __str__(self):
val = f"{{{self.key}:{self.value}}}"
return val
def __repr__(self):
val = f"{{{self.key}:{self.value}}}"
return val
class LFUNode(Node):
def __init__(self, key: Any, value: Any):
super().__init__(key, value)
self.freq: int = 0
class LinkedList(object):
def __init__(self, capacity: int = 0xffff):
self.capacity: int = capacity
self.head: Union[Node, LFUNode] = None
self.tail: Union[Node, LFUNode] = None
self.size: int = 0
# 从头部添加结点
def __add_head(self, node: Union[Node, LFUNode]) -> Union[Node, LFUNode]:
if not self.head:
self.head = node
self.tail = node
self.head.prev = None
self.tail.next = None
else:
node.next = self.head
self.head.prev = node
self.head = node
self.head.prev = None
self.size += 1
return node
# 从尾部添加结点
def __add_tail(self, node: Union[Node, LFUNode]) -> Union[Node, LFUNode]:
if not self.tail:
self.tail = node
self.head = node
self.tail.next = None
self.head.prev = None
else:
node.prev = self.tail
self.tail.next = node
self.tail = node
self.tail.next = None
self.size += 1
return node
def __del_tail(self) -> Union[Node, LFUNode, None]:
if not self.tail:
return
node = self.tail
if node.prev:
self.tail = node.prev
self.tail.next = None
else:
self.head = self.tail = None
self.size -= 1
return node
def __del_head(self) -> Union[Node, LFUNode, Node]:
if not self.head:
return
node = self.head
if node.next:
self.head = node.next
self.head.prev = None
else:
self.head = self.tail = None
self.size -= 1
return node
# 任意结点删除
def __remove(self, node: Union[Node, LFUNode]) -> Union[Node, LFUNode, None]:
if self.size <= 0:
raise ValueError("链表为空!")
if not node:
node = self.tail
if node == self.tail:
self.__del_tail()
elif node == self.head:
self.__del_head()
else:
node.prev.next = node.next
node.next.prev = node.prev
self.size -= 1
return node
def pop(self) -> Union[Node, LFUNode, None]:
return self.__del_head()
def append(self, node: Union[Node, LFUNode]) -> Union[Node, LFUNode]:
return self.__add_tail(node)
def append_front(self, node: Union[Node, LFUNode]) -> Union[Node, LFUNode]:
return self.__add_head(node)
def remove(self, node: Union[Node, LFUNode] = None) -> Union[Node, LFUNode, None]:
return self.__remove(node)
def print(self):
"""调试用"""
p = self.head
line = ""
while p:
line += f"{p}"
p = p.next
if p:
line += "=>"
print(line)
FIFO 算法
from typing import Any, Union, Dict
from LinkedList import LinkedList, Node
class FIFOCache(object):
def __init__(self, capacity: int):
self.capacity: int = capacity
self.size: int = 0
self.map: Dict[Any, Node] = {}
self.list: LinkedList[Node] = LinkedList(capacity)
def get(self, key: Any) -> Union[int, Any]:
if key not in self.map:
return -1
else:
node = self.map[key]
return node.value
def put(self, key: Any, value: Any):
if self.capacity == 0:
return
if key in self.map:
node = self.map[key]
self.list.remove(node)
node.value = value
self.list.append(node)
else:
if self.size == self.capacity:
node = self.list.pop()
del self.map[node.key]
self.size -= 1
node = Node(key, value)
self.list.append(node)
self.map[key] = node
self.size += 1
def print(self):
"""调试用"""
self.list.print()
LFU 算法
from typing import Any, Dict, Union
from LinkedList import LFUNode, LinkedList
class LFUCache(object):
def __init__(self, capacity: int):
self.capacity: int = capacity
self.map: Dict[Any, LFUNode] = {}
self.freq_map: Dict[int, LinkedList] = {} # key 是频率, value 是对应的双向链表
self.size: int = 0
def __update_freq(self, node: LFUNode):
freq = node.freq
node = self.freq_map[freq].remove(node)
if self.freq_map[freq].size == 0:
del self.freq_map[freq]
freq += 1
node.freq = freq
if freq not in self.freq_map:
self.freq_map[freq] = LinkedList()
self.freq_map[freq].append(node)
def get(self, key: Any) -> Union[int, Any]:
if key not in self.map:
return -1
node = self.map[key]
self.__update_freq(node)
return node.value
def put(self, key: Any, value: Any):
if self.capacity == 0:
return
if key in self.map:
node = self.map[key]
node.value = value
self.__update_freq(node)
else:
if self.capacity == self.size:
min_freq = min(self.freq_map)
node = self.freq_map[min_freq].pop()
del self.map[node.key]
self.size -= 1
node = LFUNode(key, value)
node.freq = 1
self.map[key] = node
if node.freq not in self.freq_map:
self.freq_map[node.freq] = LinkedList()
node = self.freq_map[node.freq].append(node)
self.size += 1
def print(self):
print("****************************************")
for k in self.freq_map:
print(f"freq = {k}")
self.freq_map[k].print()
print("****************************************")
print()
LRU 算法
from typing import Any, Union, Dict
from LinkedList import Node, LinkedList
class LRUCache(object):
def __init__(self, capacity: int):
self.map: Dict[Any, Node] = {}
self.list: LinkedList[Node] = LinkedList(capacity)
def get(self, key: Any) -> Union[int, Any]:
if key in self.map:
node = self.map[key]
self.list.remove(node)
self.list.append_front(node)
return node.value
else:
return -1
def put(self, key: Any, value: Any):
if key in self.map:
node = self.map[key]
self.list.remove(node)
node.value = value
self.list.append_front(node)
else:
node = Node(key, value)
# 如果链表缓存已满
if self.list.size >= self.list.capacity:
old_node = self.list.remove()
self.map.pop(old_node.key)
self.list.append_front(node)
self.map[key] = node
def print(self):
self.list.print()
作 者:ice
个性签名:我与春风皆过客,你携秋水揽星河
---------------------------------------------------------如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦!
转载请保留原文链接及作者。