数据结构和算法专题---3、失效算法与应用

本章我们会对失效算法做个简单介绍,包括常用的失效算法(先来先淘汰(FIFO)、最久未用淘汰(LRU)、最近最少使用(LFU))的概述、实现方式、典型场景做个说明。

什么是失效算法

失效算法常见于缓存系统中。因为缓存往往占据大量内存,而内存空间是相对昂贵,且空间有限的,那么针对一部分值,就要依据相应的算法进行失效或移除操作。

先来先淘汰(FIFO)

概述

First In First Out,先来先淘汰。这种算法在每一次新数据插入时,如果队列已满,则将最早插入的数据移除。

实现

可以方便的借助LinkedList来实现:
我们借助一个案例来进行理解,可以重点关注下注释

package com.ls.cloud.sys.alg.release;import java.util.Iterator;
import java.util.LinkedList;public class FIFO {LinkedList<Integer> fifo = new LinkedList<Integer>();int size = 3;//添加元素public void add(int i){fifo.addFirst(i);if (fifo.size() > size){fifo.removeLast();}print();}//缓存命中public void read(int i){Iterator<Integer> iterator = fifo.iterator();while (iterator.hasNext()){int j = iterator.next();if (i == j){System.out.println("find it!");print();return ;}}System.out.println("not found!");print();}//打印缓存public void print(){System.out.println(this.fifo);}//测试public static void main(String[] args) {FIFO fifo = new FIFO();System.out.println("add 1-3:");// 添加1-3fifo.add(1);fifo.add(2);fifo.add(3);System.out.println("add 4:");// 添加4,会挤出第一个进入的1fifo.add(4);System.out.println("read 2:");// 读取2,进行遍历,先进来的先打印fifo.read(2);System.out.println("read 100:");// 读取100,进行遍历,先进来的先打印fifo.read(100);System.out.println("add 5:");// 添加4,会挤出第一个进入的2fifo.add(5);}
}

结果

add 1-3:
[1]
[2, 1]
[3, 2, 1]
add 4:
[4, 3, 2]
read 2:
find it!
[4, 3, 2]
read 100:
not found!
[4, 3, 2]
add 5:
[5, 4, 3]

优缺点

  • 实现非常简单
  • 不管元素的使用情况,哪怕有些数据会被频繁用到,时间最久也会被踢掉

最久未用淘汰(LRU)

概述

LRU全称是Least Recently Used,即淘汰最后一次使用时间最久远的数值。FIFO非常的粗暴,不管有没有用到,直接踢掉时间久的元素。而LRU认为,最近频繁使用过的数据,将来也很大程度上会被频繁用到,故而淘汰那些懒惰的数据。LinkedHashMap,数组,链表均可实现LRU,下面仍然以链表为例:新加入的数据放在头部,最近访问的,也移到头部,空间满时,将尾部元素删除。

实现

同样我们借助一个案例来进行理解,可以重点关注下注释

package com.ls.cloud.sys.alg.release;import java.util.Iterator;
import java.util.LinkedList;public class LRU {LinkedList<Integer> lru = new LinkedList<Integer>();int size = 3;//添加元素public void add(int i){lru.addFirst(i);if (lru.size() > size){lru.removeLast();}print();}//缓存命中public void read(int i){Iterator<Integer> iterator = lru.iterator();int index = 0;while (iterator.hasNext()){int j = iterator.next();if (i == j){System.out.println("find it!");lru.remove(index);lru.addFirst(j);print();return ;}index++;}System.out.println("not found!");print();}//打印缓存public void print(){System.out.println(this.lru);}//测试public static void main(String[] args) {LRU lru = new LRU();System.out.println("add 1-3:");// 加入1-3,顺序加入lru.add(1);lru.add(2);lru.add(3);System.out.println("add 4:");// 加入4,踢出1lru.add(4);System.out.println("read 2:");// 读取2,2移到首位,此时变为[2,4,3]lru.read(2);System.out.println("read 100:");// 读取100,2移到首位,此时变为[2,4,3]lru.read(100);System.out.println("add 5:");// 加入5,踢出最后一个3,5加入最后,[5,2,4]lru.add(5);}
}

结果

add 1-3:
[1]
[2, 1]
[3, 2, 1]
add 4:
[4, 3, 2]
read 2:
find it!
[2, 4, 3]
read 100:
not found!
[2, 4, 3]
add 5:
[5, 2, 4]

优缺点

  • 性能较高
  • 对于偶发性、周期性的数据没有良好的抵抗力,很容易就形成缓存的污染,影响命中率

最近最少使用(LFU)

概述

Least Frequently Used,即最近最少使用。它要淘汰的是最近一段时间内,使用次数最少的值。可以认为比LRU多了一重判断。LFU需要时间和次数两个维度的参考指标。需要注意的是,两个维度就可能涉及到同一时间段内,访问次数相同的情况,就必须内置一个计数器和一个队列,计数器算数,队列放置相同计数时的访问时间。

实现

package com.ls.cloud.sys.alg.release;public class Dto implements Comparable<Dto> {private Integer key;private int count;private long lastTime;public Dto(Integer key, int count, long lastTime) {this.key = key;this.count = count;this.lastTime = lastTime;}@Overridepublic int compareTo(Dto o) {int compare = Integer.compare(this.count, o.count);return compare == 0 ? Long.compare(this.lastTime, o.lastTime) : compare;}@Overridepublic String toString() {return String.format("[key=%s,count=%s,lastTime=%s]",key,count,lastTime);}public Integer getKey() {return key;}public void setKey(Integer key) {this.key = key;}public int getCount() {return count;}public void setCount(int count) {this.count = count;}public long getLastTime() {return lastTime;}public void setLastTime(long lastTime) {this.lastTime = lastTime;}
}
package com.ls.cloud.sys.alg.release;import java.util.Collections;
import java.util.HashMap;
import java.util.Map;public class LFU {private final int size = 3;private Map<Integer,Integer> cache = new HashMap<>();private Map<Integer, Dto> count = new HashMap<>();//投放public void put(Integer key, Integer value) {Integer v = cache.get(key);if (v == null) {if (cache.size() == size) {removeElement();}count.put(key, new Dto(key, 1, System.currentTimeMillis()));} else {addCount(key);}cache.put(key, value);}//读取public Integer get(Integer key) {Integer value = cache.get(key);if (value != null) {addCount(key);return value;}return null;}//淘汰元素private void removeElement() {Dto dto  = Collections.min(count.values());cache.remove(dto.getKey());count.remove(dto.getKey());}//更新计数器private void addCount(Integer key) {Dto Dto = count.get(key);Dto.setCount(Dto.getCount()+1);Dto.setLastTime(System.currentTimeMillis());}//打印缓存结构和计数器结构private void print(){System.out.println("cache="+cache);System.out.println("count="+count);}public static void main(String[] args) {LFU lfu = new LFU();//前3个容量没满,1,2,3均加入System.out.println("add 1-3:");lfu.put(1, 1);lfu.put(2, 2);lfu.put(3, 3);lfu.print();//1,2有访问,3没有,加入4,淘汰3System.out.println("read 1,2");lfu.get(1);lfu.get(2);lfu.print();System.out.println("add 4:");lfu.put(4, 4);lfu.print();//2=3次,1,4=2次,但是4加入较晚,再加入5时淘汰1System.out.println("read 2,4");lfu.get(2);lfu.get(4);lfu.print();System.out.println("add 5:");lfu.put(5, 5);lfu.print();}
}
add 1-3:
cache={1=1, 2=2, 3=3}
count={1=[key=1,count=1,lastTime=1701744406838], 2=[key=2,count=1,lastTime=1701744406838], 3=[key=3,count=1,lastTime=1701744406838]}
read 1,2
cache={1=1, 2=2, 3=3}
count={1=[key=1,count=2,lastTime=1701744406944], 2=[key=2,count=2,lastTime=1701744406944], 3=[key=3,count=1,lastTime=1701744406838]}
add 4:
cache={1=1, 2=2, 4=4}
count={1=[key=1,count=2,lastTime=1701744406944], 2=[key=2,count=2,lastTime=1701744406944], 4=[key=4,count=1,lastTime=1701744406946]}
read 2,4
cache={1=1, 2=2, 4=4}
count={1=[key=1,count=2,lastTime=1701744406944], 2=[key=2,count=3,lastTime=1701744406947], 4=[key=4,count=2,lastTime=1701744406947]}
add 5:
cache={2=2, 4=4, 5=5}
count={2=[key=2,count=3,lastTime=1701744406947], 4=[key=4,count=2,lastTime=1701744406947], 5=[key=5,count=1,lastTime=1701744406948]}

优缺点

  • LFU也能够有效的保护缓存,相对场景来说,比LRU有更好的缓存命中率。由于是以次数为基准,因此更加准确,天然能有效的保证和提升命中率。

  • 由于LFU须要记录数据的访问频率,所以需要额外的空间;当访问模式改变的时候,算法命中率会急剧降低,这也是他最大弊端。

应用场景

redis属于缓存失效的典型应用场景,常见策略如下:

  • noeviction: 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息( 比较危险)。
  • allkeys-lru:对所有key,优先删除最近最少使用的 key (LRU)。
  • allkeys-random: 对所有key, 随机删除一部分(听起来毫无道理)。
  • volatile-lru:只限于设置了 expire 的key,优先删除最近最少使用的key (LRU)。
  • volatile-random:只限于设置了 expire 的key,随机删除一部分。
  • volatile-ttl:只限于设置了 expire 的key,优先删除剩余时间(TTL) 短的key。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/200272.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux下的java环境搭建

1&#xff0c;安装jdk 上传linux使用的jdk到/opt目录下 解压tar -zxvf文件 配置环境变量 vim /etc/profile 在文件中添加 export JAVA_HOME/opt/jdk8 export PATH$PATH:$JAVA_HOME/bin 使文件生效 source /etc/profile 2,安装tomcat 将tomcat包解压&#xff0c;进入bi…

使用gunicorn部署django项目时,发现静态文件加载失败问题

本文主要介绍如何配置Niginx加载Django的静态资源文件&#xff0c;也就是Static 1、首先需要将Django项目中的Settings.py 文件中的两个参数做以下设置&#xff1a; STATIC_URL /static/ STATIC_ROOT os.path.join(BASE_DIR, static) 2、将 STATICFILES_DIRS [ os.p…

上午面了个腾讯拿 38K 出来的,让我见识到了基础的天花板

今年的校招基本已经进入大规模的开奖季了&#xff0c;很多小伙伴收获不错&#xff0c;拿到了心仪的 offer。 各大论坛和社区里也看见不少小伙伴慷慨地分享了常见的面试题和八股文&#xff0c;为此咱这里也统一做一次大整理和大归类&#xff0c;这也算是划重点了。 俗话说得好…

智能优化算法应用:基于金鹰算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于金鹰算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于金鹰算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.金鹰算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

混音编曲软件tudio One 6.5.1 保姆级安装教程

根据软件大数据显示De-Esser驯服人声嘶嘶声和其他高频声音&#xff0c;和其他 Studio One 中新的去实体插件一样高效且直观易用&#xff0c;使用“收听”按钮查找有问题的频率&#xff0c;然后使用相关的旋钮和 S-Mon 功能拨入 S-Reduce 量即可。实际上我们可以这样讲工作流和协…

【深度学习笔记】08 欠拟合和过拟合

08 欠拟合和过拟合 生成数据集对模型进行训练和测试三阶多项式函数拟合&#xff08;正常&#xff09;线性函数拟合&#xff08;欠拟合&#xff09;高阶多项式函数拟合&#xff08;过拟合&#xff09; import math import numpy as np import torch from torch import nn from d…

国产Euler(欧拉)系统安装docker

国产的真™难用呀 生态又差还不开源 血泪经验 解压Docker安装包。 tar zxf docker-19.03.10.tgz 将解压后目录中的文件移动到“/usr/bin”下。 cp docker/* /usr/bin配置docker.service文件。 编辑docker.service文件。 vim /usr/lib/systemd/system/docker.service添加以…

公有云迁移研究——AWS Translate

大纲 1 什么是Translate2 Aws Translate是怎么运作的3 Aws Translate和Google Translate的区别4 迁移任务4.1 迁移原因 5 Aws Translate的Go demo6 迁移中遇到的问题6.1 账号和权限问题&#xff1a;6.2 小语种 1 什么是Translate Translate是一种文本翻译服务&#xff0c;它使…

常用到的设计模式(1)

单例模式 所谓单例模式&#xff0c;就是确保一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点。单例模式又分为饿汉式单例和懒汉式单例。 饿汉式 第一次引用该类的时候就创建对象实例&#xff0c;而不管实际是否需要创建。 public class Test {private static …

linux 编译安装libzmq

准备工作 sudo apt-get install autoconf automake libtool 下载源码 git clone https://github.com/zeromq/libzmq.git 编译 cd libzmq ./autogen.sh ./configure && make check sudo make install sudo ldconfig测试 cd tests ./test_msg_init结果&#xff1a;…

xcode opencv

1、导入报错 Undefined symbols: linker command failed with exit code 1 (use -v to see invocation) 直接添加如下图内容即可

<JavaEE> synchronized关键字和锁机制 -- 锁的特点、锁的使用、锁竞争和死锁、死锁的解决方法

目录 一、synchronized 关键字简介 二、synchronized 的特点 -- 互斥 三、synchronized 的特点 -- 可重入 四、synchronized 的使用示例 4.1 修饰代码块 - 锁任意实例 4.2 修饰代码块 - 锁当前实例 4.3 修饰普通方法 - 锁方法所在实例 4.4 修饰代码块 - 锁指定类对象 …

【从零开始学习JVM | 第二篇】字节码文件的组成

前言&#xff1a; 字节码作为JAVA跨平台的主要原因&#xff0c;熟练的掌握JAVA字节码文件的组成可以帮助我们解决项目的各种问题&#xff0c;并且在面试中&#xff0c;关于字节码部分的内容却是一大考点和难点&#xff0c;因此我们在这里穿插讲解一下字节码文件的组成。 目录 …

16、观察者模式(Observer Pattern)

观察者&#xff08;Observer Pattern&#xff09; 定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新。主要解决一个对象状态改变给其他对象通知的问题&#xff0c;而且要考虑到易用和低耦合&…

关于回收套接字和释放上下文的顺序

关于回收套接字和释放上下文的顺序 回收套接字和释放上下文的顺序是为了确保正确的资源管理和避免悬空指针或内存泄漏等问题。顺序如下&#xff1a; 套接字的回收&#xff1a;在网络编程中&#xff0c;使用套接字进行通信后&#xff0c;应该及时关闭套接字以释放系统资源。这可…

你好!哈希表【JAVA】

1.初识&#x1f3b6;&#x1f3b6;&#x1f3b6; 它基本上是由一个数组和一个哈希函数组成的。哈希函数将每个键映射到数组的特定索引位置&#xff0c;这个位置被称为哈希码。当我们需要查找一个键时&#xff0c;哈希函数会计算其哈希码并立即返回结果&#xff0c;因此我们可以…

【OpenGauss源码学习 —— (RowToVec)算子】

VecToRow 算子 概述ExecInitRowToVec 函数ExecRowToVec 函数VectorizeOneTuple 函数 ExecEndRowToVec 函数总结 声明&#xff1a;本文的部分内容参考了他人的文章。在编写过程中&#xff0c;我们尊重他人的知识产权和学术成果&#xff0c;力求遵循合理使用原则&#xff0c;并在…

github首次将文件合到远端分支,发现名字不是master,而是main

暂存区和本地仓库的信息都存储在.git目录中其中 其中&#xff0c;暂存区和本地仓库的信息都存储在.git目录中 在自己的github上实践 1、刚开始&#xff0c;git clone gitgithub.com:lingze8678/my_github.git到本地 2、在克隆后的代码中加入一个pdf文件 3、在git bash中操作…

【Python函数】匿名函数

定义&#xff1a; 短小的回调函数好处&#xff1a; 省去定义函数的步骤&#xff0c;更加简洁 生命周期&#xff1a; 使用时定义-调用完返回函数本身以及内存位置<function <lambda> at xxxx> 语法&#xff1a;lambda [ar1[,arg2]]: expression arguments是参数expr…

CentOS增加虚拟内存 (Linux增加内存)

前言 因为囊中羞涩不敢言&#xff0c;所以内存只有2G&#xff0c;项目在运行的时候&#xff0c;占用的内存已经报表&#xff0c;所以有的时候就会出现宕机的情况发生&#xff0c;后面发现可以通过使用增加虚拟内存空间&#xff0c;来增加内存容量。 下面进入正题&#xff0c;讲…