LRU算法及其优化策略——算法篇LRU算法全称是最近最少使用算法(LeastRecentlyUse),广泛的应用于缓

如果一个信息项正在被访问,那么在近期它很可能还会被再次访问。

所以顾名思义,LRU算法会选出最近最少使用的数据进行淘汰。

当数据的总量达到上限后,则移除容器中优先级最低的数据。下图是一个简单的LRU原理示意图:

如果我们按照70120304的顺序来访问数据,且数据的总量上限为3,则如上图所示,LRU算法会依次淘汰712这三个数据。

那么我们现在就按照上面的原理,实现一个朴素的LRU算法。下面有三种方案:

下面我们就基于双向链表和哈希表实现一个LRU算法

其实我们可以直接根据JDK给我们提供的LinkedHashMap直接实现LRU。因为LinkedHashMap的底层即为双向链表和哈希表的组合,所以可以直接拿来使用。

publicclassLRUCacheextendsLinkedHashMap{privateintcapacity;publicLRUCache(intcapacity){//注意这里将LinkedHashMap的accessOrder设为truesuper(16,0.75f,true);this.capacity=capacity;}@OverrideprotectedbooleanremoveEldestEntry(Map.Entryeldest){returnsuper.size()>=capacity;}}默认LinkedHashMap并不会淘汰数据,所以我们重写了它的removeEldestEntry()方法,当数据数量达到预设上限后,淘汰数据,accessOrder设为true意为按照访问的顺序排序。整个实现的代码量并不大,主要都是应用LinkedHashMap的特性。

朴素的LRU算法已经能够满足缓存的要求了,但是还是有一些不足。当热点数据较多时,有较高的命中率,但是如果有偶发性的批量操作,会使得热点数据被非热点数据挤出容器,使得缓存受到了“污染”。所以为了消除这种影响,又衍生出了下面这些优化方法。

LRU-K算法是对LRU算法的改进,将原先进入缓存队列的评判标准从访问一次改为访问K次,可以说朴素的LRU算法为LRU-1。

LRU-K算法有两个队列,一个是缓存队列,一个是数据访问历史队列。当访问一个数据时,首先先在访问历史队列中累加访问次数,当历史访问记录超过K次后,才将数据缓存至缓存队列,从而避免缓存队列被污染。同时访问历史队列中的数据可以按照LRU的规则进行淘汰。具体如下图所示:

下面我们来实现一个LRU-K缓存:

//直接继承我们前面写好的LRUCachepublicclassLRUKCacheextendsLRUCache{privateintk;//进入缓存队列的评判标准privateLRUCachehistoryList;//访问数据历史记录publicLRUKCache(intcacheSize,inthistoryCapacity,intk){super(cacheSize);this.k=k;this.historyList=newLRUCache(historyCapacity);}@OverridepublicIntegerget(Integerkey){//记录数据访问次数IntegerhistoryCount=historyList.get(key);historyCount=historyCount==null0:historyCount;historyList.put(key,++historyCount);returnsuper.get(key);}@OverridepublicIntegerput(Integerkey,Integervalue){if(value==null){returnnull;}//如果已经在缓存里则直接返回缓存中的数据if(super.get(key)!=null){returnsuper.put(key,value);;}//如果数据历史访问次数达到上限,则加入缓存IntegerhistoryCount=historyList.get(key);historyCount=historyCount==null0:historyCount;if(historyCount>=k){//移除历史访问记录historyList.remove(key);returnsuper.put(key,value);}}}上面只是个简单的模型,并没有加上必要的并发控制。

一般来讲,当K的值越大,则缓存的命中率越高,但是也会使得缓存难以被淘汰。综合来说,使用LRU-2的性能最优。

TwoQueue可以说是LRU-2的一种变种,将数据访问历史改为FIFO队列。好处的明显的,FIFO更简易,耗用资源更少,但是相比LRU-2会降低缓存命中率。

相比于上面两种优化,MultiQueue的实现则复杂的多,顾名思义,MultiQueue是由多个LRU队列组成的。每一个LRU队列都有一个相应的优先级,数据会根据访问次数计算出相应的优先级,并放在该队列中。

MultiQueue也可以看做是LRU-K的变种,将原来两个队列扩展为多个队列,好处就是无论是加入缓存还是淘汰缓存数据都变得更加细腻,但是会带来额外开销。

THE END
1.深度学习实现回归预测mob64ca1415f0ab的技术博客4.鸟群算法改进DELM 5.实验结果 6.参考文献 7.Matlab代码 1.ELM原理 ELM基础原理请参考:。 自动编码器 AE(Auto Encoder)经过训练可以将输入复制到输出。因为不需要标记数据,训练自动编码器是不受监督的。因此,将AE的思想应用到ELM中,使ELM的输入数据同样被用于输出,即输出Y=X。作为自编码器的极限学习机ELM-https://blog.51cto.com/u_16213707/12868183
2.C++实现LRU缓存算法算法软件开发其实,上面的代码,有一些毛病的。改天我会继续改进。 例如: 1:冗余操作。cached_entries完全可以用一个counter代替。 2:过度抽象。 3:Get、Put的interface不合理。如果真的去实现一个磁盘block的LRU cache,就会发现之前的接口需要重写了。 不过对于大家理解LRU算法。应该有一定的帮助的。https://www.open-open.com/lib/view/open1395712450650.html
3.数据结构与算法之LRU:实现LRU缓存算法功能(Ts,Py,Go版双向链表的操作非常繁琐,代码很容易写错, 不易调试 链表node 要存储 node.key, 否则需要遍历 data 删除 Python3 版算法实现 1 )方案1 classLRUCache:def__init__(self,length):iflength<1:raiseValueError('Invalid length')self.length=length self.data={}self.order=[]defset(self,key,value):ifkeyinselhttps://download.csdn.net/blog/column/6186626/134097112
4.Redis缓存满了怎么办?LFU 与偶尔访问一次相比,数据不会被淘汰的问题得到了解决。 LRU 算法也更合理。 在Redis 记录在每个对象的头中 LFU 源代码如下: typedef struct redisObject { unsigned type:4; unsigned encoding:4; unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or * LFU data (least significanthttps://www.tulingxueyuan.cn/tlzx/jsp/4663.html
5.LRULFUTinyLFU缓存算法实例详解GolangLFU算法 我们已经成功的写出了LRU算法(伪代码),接下来尝试自己写一下LFU算法。首先我们知道LFU算法比LRU多了什么,LFU需要记录每条数据的访问次数信息,并且按照访问次数从高到低排序,访问次数用什么来记录呢? 只需要在链表节点中增加一个访问频率Frequency,就可以了,这个Frequency可以使用int来存储。同时排序的规则稍加变https://m.jb51.net/article/262101.htm
6.Algorithm进阶计划LRU与LFU算法1.2 LRU 算法代码实现 首先构建双链表如下: /** * 双链表的节点类 */publicclassNode{publicintkey,val;publicNodenext,prev;publicNode(intk,intv){this.key=k;this.val=v;}}/** * 双链表 */publicclassDoubleList{// 头尾虚节点privateNodehead,tail;// 链表元素数privateintsize;publicDoubleList(){https://www.jianshu.com/p/95429381636f
7.面试不再怕,20行Python代码帮你搞懂LRU算法面试不再怕,20行Python代码帮你搞懂LRU算法 LRU算法在后端工程师面试中,是一个比较常出现的题目,这篇文章带大家一起,理解LRU算法,并最终用Python轻松实现一个基于LRU算法的缓存。 缓存是什么 先看一张图,当我们访问网页,浏览器会给服务器发请求,服务器会经过一系列的运算,把页面返回给浏览器。https://cloud.tencent.com/developer/article/1355345