Explicação detalhada do algoritmo LRU: estratégia de substituição de cache usada menos recentemente
introdução
Na ciência da computação, o cache é uma técnica de otimização comum usada para acelerar o acesso aos dados. Cache refere-se à memória de alta velocidade que armazena cópias de dados usados recentemente para que possam ser acessados rapidamente quando necessário. Em sistemas de computador, um dos tipos mais comuns de cache é o cache de memória, que inclui cache de páginas e cache de objetos. No cache, LRU (menos usado recentemente) é uma estratégia popular de substituição de cache. Este artigo apresentará detalhadamente o princípio e a implementação do algoritmo LRU.
Princípio do algoritmo LRU
O algoritmo LRU é baseado em um conceito simples: o princípio menos utilizado recentemente. O algoritmo acredita que os dados que foram usados recentemente também provavelmente serão usados novamente no futuro, enquanto os dados que não foram usados por um longo período de tempo têm maior probabilidade de permanecer sem uso no futuro. Portanto, o algoritmo LRU utiliza uma estratégia de substituição de cache, ou seja, os dados que não são acessados há mais tempo são eliminados do cache.
A ideia central do algoritmo LRU é manter um histórico ordenado de acesso aos dados. Quando um dado é acessado, ele é trazido para o início do histórico, enquanto os dados que não são acessados há mais tempo ficam no final do histórico. Quando o espaço de cache for insuficiente, o algoritmo LRU selecionará os dados no final do registro histórico para substituição.
Método de implementação do algoritmo LRU
Use uma lista duplamente vinculada
Uma maneira comum de implementar o algoritmo LRU é usar uma lista duplamente vinculada. O topo da lista vinculada representa os dados acessados mais recentemente, enquanto o final representa os dados que não foram acessados há mais tempo. Sempre que os dados são acessados, eles podem ser movidos para o topo da lista vinculada. Se desejar inserir novos dados, mas o cache estiver cheio, você pode optar por excluir os dados no final da lista vinculada.
A seguir está o pseudocódigo para implementar o algoritmo LRU usando uma lista duplamente vinculada:
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.cache = {}
self.head = DoubleLinkedListNode()
self.tail = DoubleLinkedListNode()
self.head.next = self.tail
self.tail.prev = self.head
def get(self, key: int) -> int:
if key in self.cache:
node = self.cache[key]
self._move_to_head(node)
return node.value
else:
return -1
def put(self, key: int, value: int) -> None:
if key in self.cache:
node = self.cache[key]
node.value = value
self._move_to_head(node)
else:
node = DoubleLinkedListNode(key, value)
self.cache[key] = node
self._add_to_head(node)
if len(self.cache) > self.capacity:
tail_node = self._remove_tail()
del self.cache[tail_node.key]
def _move_to_head(self, node: DoubleLinkedListNode) -> None:
self._remove_node(node)
self._add_to_head(node)
def _add_to_head(self, node: DoubleLinkedListNode) -> None:
node.prev = self.head
node.next = self.head.next
self.head.next.prev = node
self.head.next = node
def _remove_node(self, node: DoubleLinkedListNode) -> None:
node.prev.next = node.next
node.next.prev = node.prev
def _remove_tail(self) -> DoubleLinkedListNode:
tail_node = self.tail.prev
self._remove_node(tail_node)
return tail_node
class DoubleLinkedListNode:
def __init__(self, key=None, value=None):
self.key = key
self.value = value
self.prev = None
self.next = None
Usando tabelas hash e filas
Outra forma de implementar o algoritmo LRU é usar tabelas hash e filas. As tabelas hash podem encontrar rapidamente nós com chaves específicas, enquanto as filas podem manter a ordem em que os dados são acessados.
A seguir está o pseudocódigo para implementar o algoritmo LRU usando tabelas hash e filas:
from collections import deque
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.cache = {}
self.queue = deque()
def get(self, key: int) -> int:
if key in self.cache:
self.queue.remove(key)
self.queue.append(key)
return self.cache[key]
else:
return -1
def put(self, key: int, value: int) -> None:
if key in self.cache:
self.queue.remove(key)
elif len(self.cache) >= self.capacity:
evicted_key = self.queue.popleft()
del self.cache[evicted_key]
self.cache[key] = value
self.queue.append(key)
para concluir
O algoritmo LRU é uma estratégia de substituição de cache comumente usada que elimina dados com base no princípio dos dados usados recentemente. Ao manter um histórico de acesso ordenado, o algoritmo LRU pode efetivamente melhorar a taxa de acertos do cache. Este artigo apresenta o princípio do algoritmo LRU e dois métodos comuns de implementação: usando listas duplamente vinculadas e usando tabelas hash e filas. Os leitores podem escolher seu próprio método para implementar o cache LRU com base em cenários de aplicativos específicos.