Home > Article > Backend Development > Detailed analysis of the LRU cache algorithm in Golang.
When developing an efficient and stable system, caching is an indispensable optimization method. One of the most common caching algorithms is the LRU algorithm. The LRU algorithm is the "least recently used" algorithm. It can eliminate the least recently used elements by recording the usage of each element in the cache to maximize cache utilization efficiency. In Golang, the LRU cache algorithm can also be easily implemented.
This article will introduce in detail the implementation of the LRU cache algorithm in Golang, including how to use a doubly linked list and a hash table to implement it, how to update and eliminate the cache, and how to perform thread-safe operations.
In Golang, doubly linked lists are a basic data structure that can easily implement the LRU caching algorithm. The specific implementation method is to encapsulate each element in the cache into a node and use a doubly linked list to manage these nodes. At the same time, a hash table (map) is used to record the location of each node to facilitate quick search and update.
The following is the basic code structure for implementing the LRU cache algorithm in Golang:
type Node struct { Key int Val int Prev *Node Next *Node } type LRUCache struct { Size int Capacity int Cache map[int]*Node Head, Tail *Node } func Constructor(capacity int) LRUCache { head, tail := &Node{}, &Node{} head.Next, tail.Prev = tail, head return LRUCache{ Cache: make(map[int]*Node), Capacity: capacity, Size: 0, Head: head, Tail: tail, } } func (l *LRUCache) Get(key int) int { if node, ok := l.Cache[key]; ok { l.MoveToHead(node) return node.Val } return -1 } func (l *LRUCache) Put(key, val int) { if node, ok := l.Cache[key]; ok { node.Val = val l.MoveToHead(node) return } node := &Node{Key: key, Val: val} l.Cache[key] = node l.AddToHead(node) l.Size++ if l.Size > l.Capacity { removed := l.RemoveTail() delete(l.Cache, removed.Key) l.Size-- } } func (l *LRUCache) MoveToHead(node *Node) { l.RemoveNode(node) l.AddToHead(node) } func (l *LRUCache) RemoveNode(node *Node) { node.Prev.Next = node.Next node.Next.Prev = node.Prev } func (l *LRUCache) AddToHead(node *Node) { node.Prev = l.Head node.Next = l.Head.Next l.Head.Next.Prev = node l.Head.Next = node } func (l *LRUCache) RemoveTail() *Node { node := l.Tail.Prev l.RemoveNode(node) return node }
In the above code, LRUCache
is a structure containing a Cache
Hash table, a Head
pointer and a Tail
pointer, used to record the head and tail nodes of the doubly linked list and the position of each element in the cache. Among them, the key of the Cache
hash table is the key of the element, and the value is the node pointer of the element; Head
points to the head node of the doubly linked list, and Tail
points to the tail node. . Size
indicates the number of elements in the current cache, and Capacity
indicates the maximum capacity of the cache.
In the Constructor
function, we initialize an empty doubly linked list and return a LRUCache
structure. In the Get
function, we first determine whether the specified element exists in the cache. If it exists, move the element to the head of the linked list and return its value; otherwise, return -1. In the Put
function, we first determine whether the specified element exists in the cache. If it exists, update the value of the element and move it to the head; otherwise, add a new element and add it to the head. If the cache size exceeds the maximum capacity, the least recently used element is removed and removed from the hash table.
MoveToHead
, RemoveNode
, AddToHead
and RemoveTail
respectively correspond to the node movement and deletion operations of the doubly linked list, specifically The implementation is given in the code.
When using the LRU cache algorithm, it is necessary to ensure that the access sequence of elements in the cache is arranged in the most recently used time order. Whenever an element is read or updated from the cache, it needs to be moved to the head of the linked list; at the same time, when the cache size exceeds the maximum capacity, the least recently used element, that is, the last element in the linked list, needs to be eliminated.
The following is the implementation of the MoveToHead
function:
func (l *LRUCache) MoveToHead(node *Node) { l.RemoveNode(node) l.AddToHead(node) }
MoveToHead
The function accepts a pointer to the cache node node
as Parameters, first delete the node from the linked list, and then add the node to the head of the linked list.
The following is the implementation of the RemoveTail
function:
func (l *LRUCache) RemoveTail() *Node { node := l.Tail.Prev l.RemoveNode(node) return node }
RemoveTail
The function returns the last node in the linked list and removes the node from the linked list delete.
In a multi-threaded environment, it is necessary to ensure the thread safety of LRU cache operations. To do this, we can use the mutex provided in the sync package. The specific method is to add mutex lock operations to functions that require cache operations to avoid simultaneous read and write operations on the cache. The following is the code structure for implementing the thread-safe version of the LRU cache algorithm in Golang:
type LRUCache struct { Size int Capacity int Cache map[int]*Node Head, Tail *Node Mutex sync.Mutex } func (l *LRUCache) Get(key int) int { l.Mutex.Lock() defer l.Mutex.Unlock() ... } func (l *LRUCache) Put(key, val int) { l.Mutex.Lock() defer l.Mutex.Unlock() ... } ...
In the above code, we added a Mutex
to the structure LRUCache
Member for synchronizing mutexes on cache operations. Before doing any caching operation, we need to obtain the mutex lock. In any case, whether reading or modifying the cache, we need to release the mutex.
This article introduces the implementation of the LRU cache algorithm in Golang, including the use of a doubly linked list and a hash table to implement it, cache update and elimination, and Thread safe operation. The LRU cache algorithm is a simple and efficient cache algorithm that is widely used in actual development. When using Golang to write cache applications, you can use the LRU cache algorithm to improve system performance and stability according to actual needs.
The above is the detailed content of Detailed analysis of the LRU cache algorithm in Golang.. For more information, please follow other related articles on the PHP Chinese website!