用 Go 实现一个 LRU cache

crossoverJie · · 983 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

![](https://tva1.sinaimg.cn/large/008i3skNly1gxjigld2hvj30rs0rsmy9.jpg) # 前言 早在几年前写过关于 `LRU cache` 的文章: [https://crossoverjie.top/2018/04/07/algorithm/LRU-cache/](https://crossoverjie.top/2018/04/07/algorithm/LRU-cache/) 当时是用 Java 实现的,最近我在完善 [ptg](https://github.com/crossoverJie/ptg) 时正好需要一个最近最少使用的数据结构来存储历史记录。 > ptg: Performance testing tool (Go), 用 Go 实现的 gRPC 客户端调试工具。 Go 官方库中并没有相关的实现,考虑到程序的简洁就不打算依赖第三方库,自己写一个;本身复杂度也不高,没有几行代码。 配合这个数据结构,我便在 [ptg](https://github.com/crossoverJie/ptg) 中实现了请求历史记录的功能: > 将每次的请求记录存储到 lru cache 中,最近使用到的历史记录排在靠前,同时也能提供相关的搜索功能;具体可见下图。 ![](https://tva1.sinaimg.cn/large/008i3skNly1gxjmfnemtdg30go0dpn6d.gif) # 实现 ![](https://tva1.sinaimg.cn/large/008i3skNly1gxjj4bey8pj30bh06rglp.jpg) 实现原理没什么好说的,和 `Java` 的一样: - 一个双向链表存储数据的顺序 - 一个 `map` 存储最终的数据 - 当数据达到上限时移除链表尾部数据 - 将使用到的 `Node` 移动到链表的头结点 虽然 Go 比较简洁,但好消息是基本的双向链表结构还是具备的。 ![](https://tva1.sinaimg.cn/large/008i3skNly1gxjk38rqvij311q0ki40l.jpg) 所以基于此便定义了一个 `LruCache`: ![](https://tva1.sinaimg.cn/large/008i3skNly1gxjk56jwldj30ua0j8q4m.jpg) 根据之前的分析: - `size` 存储缓存大小。 - 链表存储数据顺序。 - `map` 存储数据。 - `lock` 用于控制并发安全。 ![](https://tva1.sinaimg.cn/large/008i3skNly1gxk7hvjfbrj30gs0da75g.jpg) 接下来重点是两个函数:写入、查询。 写入时判断是否达到容量上限,达到后删除尾部数据;否则就想数据写入头部。 而获取数据时,这会将查询到的结点移动到头结点。 这些结点操作都由 List 封装好了的。 ![](https://tva1.sinaimg.cn/large/008i3skNly1gxjkyun5nhj30n00gqgne.jpg) 所以使用起来也比较方便。 最终就是通过这个 `LruCache` 实现了上图的效果,想要了解更多细节的可以参考源码: [https://github.com/crossoverJie/ptg/blob/main/gui/lru.go](https://github.com/crossoverJie/ptg/blob/main/gui/lru.go)

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

983 次点击  
加入收藏 微博
1 回复  |  直到 2021-12-21 16:13:16
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传