背景
在我们这个日益追求高效的世界,我们对任何事情的等待都显得十分的浮躁,网页页面刷新不出来,好烦,电脑打开运行程序慢,又是好烦!那怎么办,技术的产生不就是我们所服务么,今天我们就聊一聊缓存这个技术,并使用我们熟知的数据结构--用链表实现LRU缓存淘汰算法。
在学习如何使用链表实现LRU缓存淘汰算法前,我们先提出几个问题,大家好好思考下,问题如下:
- 什么是缓存,缓存的作用?
- 缓存的淘汰策略有哪些?
- 如何使用链表实现LRU缓存淘汰算法,有什么特点,如何优化?
好了,我们带着上面的问题来学进行下面的学习。
1、什么是缓存,缓存的作用是什么?
缓存可以简单地理解为保存数据的一个副本,以便于后续能够快速地进行访问。以计算机的使用场景为例,当cpu要访问内存中的一条数据时,它会先在缓存里查找,如果能够找到则直接使用,如果没找到,则需要去内存里查找;
同样的,在数据库的访问场景中,当项目系统需要查询数据库中的某条数据时,可以先让请求查询缓存,如果命中,就直接返回缓存的结果,如果没有命中,就查询数据库, 并将查询结果放入缓存,下次请求时查询缓存命中,直接返回结果,就不用再次查询数据库。
通过以上两个例子,我们发现无论在哪种场景下,都存在这样一个顺序:先缓存,后内存;先缓存,后数据库。但是缓存的存在也占用了一部分内存空间,所以缓存是典型的以空间换时间,牺牲数据的实时性,却满足计算机运行的高效性。
仔细想一下,我们日常开发中遇到缓存的例子还挺多的。
- 操作系统的缓存
减少与磁盘的交互
- 数据库缓存
减少对数据库的查询
- Web服务器缓存
减少对应用服务器的请求
- 客户浏览器的缓存
减少对网站的访问
2、缓存有哪些淘汰策略?
缓存的本质是以空间换时间,那么缓存的容量大小肯定是有限的,当缓存被占满时,缓存中的那些数据应该被清理出去,那些数据应该被保留呢?这就需要缓存的淘汰策略来决定。
事实上,常用的缓存的淘汰策略有三种:先进先出算法(First in First out FIFO);淘汰一定时期内被访问次数最少的页面(Least Frequently Used LFU);淘汰最长时间未被使用的页面(Least Recently Used LRU)
这些算法在不同层次的缓存上执行时具有不同的效率,需要结合具体的场景来选择。
2.1 FIFO算法
FIFO算法即先进先出算法,常采用队列实现。在缓存中,它的设计原则是:如果一个数据最先进入缓存中,则应该最早淘汰掉。
FIFO算法
新访问的数据插入FIFO队列的尾部,队列中数据由队到队头按顺序顺序移动
队列满时,删除队头的数据
2.2 LRU算法
LRU算法是根据对数据的历史访问次数来进行淘汰数据的,通常使用链表来实现。在缓存中,它的设计原则是:如果数据最近被访问过,那么将来它被访问的几率也很高。
LRU算法
- 新加入的数据插入到链表的头部
- 每当缓存命中时(即缓存数据被访问),则将数据移到链表头部 <