IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 基于 golang 实现 LRU 算法 -> 正文阅读

[数据结构与算法]基于 golang 实现 LRU 算法

前言

在地址映射过程中,若发现所要访问的页面不在内存中,则产生缺页中断。当发生缺页中断时,如果操作系统内存中没有空闲页面,则操作系统必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。而用来选择淘汰哪一页的规则叫做页面置换算法。


一、LRU算法是什么?

LRU 是 Least Recently Used 的缩写,即最近最少使用,是一种常见的页面置换算法。LRU 算法的基本理念是:最近使用的数据在未来一段时间仍会被使用,已经很久没有使用的数据可能在未来较长的一段时间内不会被使用。所以在需要淘汰页面时,每次选择淘汰最久没有被访问的页面。

二、基于 golang 的实现

1.构建结构体

通过 golang 内置的双向链表 list.List 存储每个节点,同时维护一个哈希表,可快速判断需要加载的数据是否已经在链表中存在,无须遍历链表查找,典型的以空间换时间的方式。

type LRU struct {
	maxByte int64                    //最多存储数据的字节个数,超过此数量便会触发数据的淘汰
	curByte int64                    //目前存储的字节个数
	list    *list.List               //使用go语言内置的双向链表存储节点
	cache   map[string]*list.Element //通过节点的key快速定位到属于哪个节点,不需遍历双向链表
	mu      sync.RWMutex             //读写锁,保证并发安全
}

type Entry struct {
	Key   string //每个节点的唯一标识,作为key储存到lru的cache里
	Value []byte //携带的数据
}

// New Constructor of LRU
func New(maxByte int64) *LRU {
	return &LRU{
		maxByte: maxByte,
		curByte: 0,
		list:    list.New(),
		cache:   make(map[string]*list.Element),
	}
}

2.读取数据

输入 key 查找数据,直接根据 key 去哈希表中查找,查找成功则将此节点转移至双向链表头部,并返回存储的数据,反之返回查找失败。

// Get look up a key`s value
func (l *LRU) Get(key string) ([]byte, bool) {
	l.mu.RLock()
	defer l.mu.RUnlock()

	if ele, exist := l.cache[key]; exist {
		l.list.MoveToFront(ele) //此元素被访问,移动到链表最前面
		if entry, ok := ele.Value.(*Entry); ok {
			return entry.Value, true
		}
	}

	return nil, false
}

3.淘汰数据

每次淘汰双向链表尾部数据,更新哈希表,删除该节点 key 对应的 value,最后更新 lru 结构体已用字节数。

// RemoveOldest remove entry from linklist back
func (l *LRU) removeOldest() {
	ele := l.list.Back() //取出链表尾部节点
	if ele != nil {
		l.list.Remove(ele) //删除节点
		if entry, ok := ele.Value.(*Entry); ok {
			delete(l.cache, entry.Key)                                   //哈希表删除该节点key
			l.curByte -= int64(len(entry.Key)) + int64(len(entry.Value)) // 调整已使用字节数
		}
	}
}

4.新增数据

数据新增时,需要判断该数据是否已存在,存在则移动到链表头部,并更新使用字节数。不存在则直接插入头部,并更新哈希表。最后根据最大字节数和已使用字节数比较,判断是否需要淘汰数据。

// Add a value to lru
func (l *LRU) Add(key string, value []byte) {
	l.mu.Lock()
	defer l.mu.Unlock()

	// 两种情况
	if ele, ok := l.cache[key]; ok {
		l.list.MoveToFront(ele)
		if entry, ok := ele.Value.(*Entry); ok {
			l.curByte += int64(len(value)) - int64(len(entry.Value)) // value改变的话需要改变已用字节数
			entry.Value = value
		}
	} else {
		ele := l.list.PushFront(&Entry{Key: key, Value: value})
		l.cache[key] = ele
		l.curByte = int64(len(key)) + int64(len(value))
	}

	// 已使用字节数大于最大字节数时,需要移除链表尾部节点,直到已使用字节数小于最大字节数
	for l.maxByte > 0 && l.maxByte < l.curByte {
		l.RemoveOldest()
	}
}

总结

以上便是此次 golang 实现 lru 算法的全部内容,源代码和测试代码都放在了我的 github 仓库中。github地址:golang 实现 lru 算法,欢迎前往查看,点个 statr 。有问题的话可以评论区讨论。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-11-22 12:35:49  更:2021-11-22 12:37:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/9 15:28:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码