手撕LRU代码

简介: 手撕LRU代码

原理

LRU(Least Recently Used)最近最少使用,用于缓存淘汰策略,就是把最近最少使用的数据移除内存,以加载其他数据

  1. 添加元素时,放到链表头
  2. 缓存命中将元素移动到链表中
  3. 缓存满了之后,将链表尾的元素删除

原理清楚了,代码其实就是双向链表和map,然后根据需求写代码即可

代码

package main
import (
  "container/list"
  "fmt"
  "sync"
)
type LRU struct {
  max   int                                      //存储key的最大数量
  list  *list.List                               //双向链表
  Call  func(key interface{}, value interface{}) //淘汰kv时的回调函数
  cache map[interface{}]*list.Element            //缓存
  mu    *sync.Mutex                              //互斥锁
}
type Node struct {
  Key interface{}
  Val interface{}
}
// NewLRU 返回一个LRU的实例
func NewLRU(len int) *LRU {
  return &LRU{
    max:   len,
    list:  list.New(),
    Call:  nil,
    cache: make(map[interface{}]*list.Element),
    mu:    new(sync.Mutex),
  }
}
// Add 添加一个kv到缓存中
func (lru *LRU) Add(key, val interface{}) error {
  lru.mu.Lock()
  defer lru.mu.Unlock()
  //如果存在则更新,并将结点移到最前面
  if e, ok := lru.cache[key]; ok {
    e.Value.(*Node).Val = val
    lru.list.MoveToFront(e)
    return nil
  }
  //如果不存在则头插到双向链表中
  e := lru.list.PushFront(&Node{
    Key: key,
    Val: val,
  })
  //添加至缓存中
  lru.cache[key] = e
  //如果元素的数量超过最大值了,那么把末端的淘汰
  if lru.max != 0 && lru.list.Len() > lru.max {
    if e := lru.list.Back(); e != nil {
      lru.list.Remove(e)
      node := e.Value.(*Node)
      delete(lru.cache, node.Key)
      if lru.Call != nil {
        lru.Call(node.Key, node.Val)
      }
    }
  }
  return nil
}
func (lru *LRU) Get(key interface{}) (val interface{}, ok bool) {
  lru.mu.Lock()
  defer lru.mu.Unlock()
  //如果存在,先把该kv移到链表头部再返回
  if e, ok := lru.cache[key]; ok {
    lru.list.MoveToFront(e)
    return e.Value.(*Node).Val, true
  }
  return
}
func (lru *LRU) GetAll() (data []*Node) {
  lru.mu.Lock()
  defer lru.mu.Unlock()
  for _, v := range lru.cache {
    data = append(data, v.Value.(*Node))
  }
  return data
}
func (lru *LRU) Del(key interface{}) {
  lru.mu.Lock()
  defer lru.mu.Unlock()
  if e, ok := lru.cache[key]; ok {
    lru.list.Remove(e)
    node := e.Value.(*Node)
    delete(lru.cache, node.Key)
    if lru.Call != nil {
      lru.Call(node.Key, node.Val)
    }
  }
}
func main() {
  lru := NewLRU(3)
  lru.Add("w", "1")
  lru.Add("x", "2")
  lru.Add("f", "3")
  lru.Add("c", "4")
  lru.Add("s", "5")
  for _, node := range lru.GetAll() {
    fmt.Println(node)
  }
  fmt.Println("~~~分割线~~~")
  lru.Del("f")
  for _, node := range lru.GetAll() {
    fmt.Println(node)
  }
  fmt.Println("~~~分割线~~~")
  lru.Add("qq", "68725032")
  for _, node := range lru.GetAll() {
    fmt.Println(node)
  }
}


目录
相关文章
|
机器学习/深度学习 自然语言处理 PyTorch
VLLM (Very Large Language Model)
VLLM (Very Large Language Model) 是一种大型语言模型,通常具有数十亿或数万亿个参数,用于处理自然语言文本。VLLM 可以通过预训练和微调来执行各种任务,如文本分类、机器翻译、情感分析、问答等。
1094 1
|
缓存 自然语言处理 物联网
LLama Factory+ModelScope实战——使用 Web UI 进行监督微调
LLaMA Factory 是一个高效的大语言模型训练和推理框架,它通过提供一站式的 Web UI 界面和集成多种训练方法,简化了大模型的微调过程,并能够适配多种开源模型。
|
3月前
|
关系型数据库 MySQL 数据库
MySQL报错:未知系统变量'tx_isolation'及隔离级别查询
记住,选择合适的隔离级别,就像是在风平浪静的湖面上找到适合的划船速度——既要快到能赶上午饭(性能),又不至于翻船(数据一致性问题)。
179 3
|
8月前
|
机器学习/深度学习 人工智能 自然语言处理
从原理出发 - 提示词如何影响大模型的输出
在探索人工智能的深海中,提示词(Prompt)是引导大模型输出的灯塔。本文希望通过对自身所学所思进行总结,解析提示词如何塑造AI的响应,揭示其背后的机制。
524 10
|
JavaScript Java 测试技术
基于Java的点餐系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的点餐系统的设计与实现(源码+lw+部署文档+讲解等)
206 0
|
10月前
|
Java
线程池内部机制:线程的保活与回收策略
【10月更文挑战第24天】 线程池是现代并发编程中管理线程资源的一种高效机制。它不仅能够复用线程,减少创建和销毁线程的开销,还能有效控制并发线程的数量,提高系统资源的利用率。本文将深入探讨线程池中线程的保活和回收机制,帮助你更好地理解和使用线程池。
455 2
|
资源调度 算法 定位技术
|
安全 数据安全/隐私保护
HTTPS加密的过程
HTTPS加密的过程
|
安全 算法 数据安全/隐私保护
HTTPS 加密工作过程
HTTPS 加密工作过程
|
安全 算法 数据安全/隐私保护
【C++入门到精通】智能指针 shared_ptr 简介及C++模拟实现 [ C++入门 ]
【C++入门到精通】智能指针 shared_ptr 简介及C++模拟实现 [ C++入门 ]
344 0