高并发下的分布式缓存 | 设计和实现LRU缓存

news2025/1/24 11:49:25

LRU缓存介绍

什么是LRU缓存?

LRU缓存是一种缓存策略,当缓存满了,需要腾出空间存放新数据时,它会删除最近最少使用的数据。换句话说,它会优先淘汰那些最久没有被访问的元素,以确保缓存中的数据是最近使用的,这对提高缓存系统的命中率有帮助。

让我们通过一个例子来理解LRU

假设内存中有5个远端,缓存的大小为 3.

最初缓存是空的,所有元素都存在内存中,我们先访问内存中元素A1,并将其放入缓存中。

接下来,我们访问内存中的元素A2将其放入缓存,A2存储在 最顶端,此时,缓存中的A1下移,因为A1不再是最近访问的元素了。

接下来,我们访问内存中的元素A3,过程与访问A2类似,此时A3位于缓存顶端,A1,A2下移。

现在,我们再次访问A2,我们可以从缓存中获取了,而不是从内存中获取,但是需要注意的是,获取到A2之后,需要将A2移动到缓存的顶部,因为A2是目前最近访问过的元素。

现在,我们访问A4,我们必须从内存中获取它,但是我们将它放到缓存中的哪个位置了,现在缓存已经满了,我们必须删除一些元素以便容纳A4,在本例中,我们删除了最近最少使用的A1,这就是最近最少使用(LRU)算法。

LRU缓存实现

如何设计一个LRU缓存:

如何设计一个支持以下操作的LRU缓存:

  1. LRUCache(int capacity):初始化LRU缓存,并设定缓存的容量。
  2. int get(int key):如果key存在于缓存中,返回它对应的value;如果不存在,返回-1。
  3. void put(int key, int value):如果key已经在缓存中,更新它的value;如果key不在缓存中,将新的key-value对加入缓存。如果缓存满了,需要先移除最近最少使用的元素,再插入新的key-value对。

要求:

  1. 访问和更新缓存中的元素,时间复杂度为O(1)。
  2. 删除缓存中最久未使用的元素,时间复杂度也为O(1)。

方式一:使用数组实现LRU缓存

使用一个固定大小的数组存储缓存中的元素,每个元素除了存储key和value外,还存储一个时间戳timeStamp,标记元素的访问时间。当我们访问或插入一个元素时,更新该元素的时间戳,以表示它是最近使用过的。当缓存满时,我们需要找到时间戳最大的元素(表示最久未使用),将其删除,然后插入新元素。

class DataElement {
    int key;
    int value;
    int timeStamp;

    public DataElement(int k, int data, int time) {
        key = k;
        value = data;
        timeStamp = time;
    }
}

这种方式的问题是:

  1. 每次访问元素需要遍历数组,这个时间复杂度为O(n)。
  2. 如果缓存已满需要为新元素腾出空间时,需要遍历数组找到最久未使用的元素。这个时间复杂度为O(n),非常低效。

方式二:使用单链表实现LRU缓存

使用单链表存储缓存中的元素,链表头部是最近使用的元素,尾部是最久未使用的元素。每次访问或插入元素时,将该元素移到链表头部。

这种方式get和put操作的时间复杂度都是O(n):

  1. 从缓存中获取指定元素时,需要遍历链表,时间复杂度是O(n)。
  2. 插入元素到缓存中,如果缓存已满,需要删除最近最少使用的 缓存,也就是尾部的元素,为此,需要遍历链表到达末尾,时间复杂度也是O(n)。

方式三:使用哈希表和双向链表实现LRU缓存

我们需要结合双向链表和哈希表来实现LRU缓存。

查找元素

详细步骤:

  1. 在哈希表中查找是否存在该key。
  2. 如果存在,表示缓存命中(cache hit),我们将对应的节点移动到链表头部(表示它是最近使用的元素)。
  3. 如果不存在,返回-1,表示缓存未命中(cache miss)。
插入元素
  1. 先查找哈希表,判断key是否已经存在。
  2. 如果存在,更新其value,并将对应节点移到链表头部。
  3. 如果不存在,检查缓存是否已满,如果未满,将新元素插入链表头部,并在哈希表中记录。
  4. 如果已满,删除链表尾部的最久未使用元素(同时删除哈希表中的对应记录),然后插入新元素到链表头部。

下面是一个LRU缓存的Java实现:

public class LRUCache {

    class Node {
        int key;
        int value;
        Node pre;
        Node post;
    }

    private Hashtable<Integer, Node> cache = new Hashtable<Integer, Node>();
    private int count;
    private int capacity;
    private Node head, tail;

    // Add the new node right after head
    private void addNode(Node node) {
        node.pre = head;
        node.post = head.post;

        head.post.pre = node;
        head.post = node;
    }

    // Remove an existing node from the linked list
    private void removeNode(Node node) {
        Node pre = node.pre;
        Node post = node.post;

        pre.post = post;
        post.pre = pre;
    }

    // Move node in between to the head
    private void moveToHead(Node node) {
        removeNode(node);
        addNode(node);
    }

    // Pop the current tail
    private Node popTail() {
        Node res = tail.pre;
        removeNode(res);
        return res;
    }

    public LRUCache(int capacity) {
        this.count = 0;
        this.capacity = capacity;

        head = new Node();
        head.pre = null;

        tail = new Node();
        tail.post = null;

        head.post = tail;
        tail.pre = head;
    }

    public int get(int key) {
        Node node = cache.get(key);

        if (node == null) {
            return -1;
        }

        moveToHead(node);
        return node.value;
    }

    public void put(int key, int value) {
        Node node = cache.get(key);

        if (node == null) {
            Node newNode = new Node();
            newNode.key = key;
            newNode.value = value;

            cache.put(key, newNode);
            addNode(newNode);

            ++count;

            if (count > capacity) {
                // Pop the tail
                Node tailNode = popTail();
                cache.remove(tailNode.key);
                --count;
            }

        } else {
            // Update the value.
            node.value = value;
            moveToHead(node);
        }
    }
}

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

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

相关文章

学习安卓开发遇到的问题

问题1&#xff1a;学习禁用与恢复按钮中&#xff1a; java代码报错&#xff1a;报错代码是 R.id.btn_enable;case R.id.btn_disable;case R.id.btn_test: 代码如下&#xff1a;&#xff08;实现功能在代码后面&#xff09; package com.example.apptest;import static java.…

04 表的操作

目录 创建查看修改删除 1. 创建 语法&#xff1a; CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储殷勤; 说明&#xff1a; field&#xff0c;表示列名 datatype&#xff0c;表示列的类型…

专题十_哈希表

目录 题型总结 1. 两数之和 解析 题解 面试题 01.02. 判定是否互为字符重排 解析 题解 217. 存在重复元素 解析 题解 219. 存在重复元素 II 解析 题解 49. 字母异位词分组 解析 题解 题型总结 1. 两数之和 1. 两数之和 解析 题解 class Solution { public:ve…

ECMAScript 12 (ES12, ES2021) 新特性

还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#xff0c;webgl&#xff0c;ech…

Rewrite功能配置

Rewrite Rewrite是Nginx服务器提供的一个重要基本功能。主要的作用是用来实现URL的重写。 Nginx服务器的Rewrite功能的实现依赖于PCRE的支持&#xff0c;因此在编译安装Nginx服务器之前&#xff0c;需要安装PCRE库。 Nginx使用的是ngx_http_rewrite_module模块来解析和处理Re…

用VBA在Word中随机打乱单词表,进行分列

一、效果展示&#xff08;以下是三次随机打乱的结果&#xff09; 二、代码 Sub 随机分单词到后面的单元格()Dim C1 As CellDim str, str1, aDim shuffledArray() As VariantSet C1 Selection.Range.Tables(1).Cell(1, 1)str C1.Range.textstr mid(str, 3, Len(str) - 4)str…

微信小程序版NetAssist局域网工具使用

微信小程序搜《TCPUDP局域网小助手》即可使用&#xff0c;电脑端&#xff0c;安卓端&#xff0c;苹果端都可以使用

【前端面试】七、算法-递归、拷贝等

目录 1.常考算法 2.遍历方法 3.链式调用 4.递归 5.拷贝和比较 1.常考算法 排序算法&#xff1a;快速排序、归并排序、堆排序等。 查找算法&#xff1a;二分查找、哈希表查找等。 动态规划&#xff1a;解决最优化问题&#xff0c;如斐波那契数列、最长公共子序列等。 图…

8.3 day bug

bug1 文件名字写错了&#xff0c;找了半天bug原因 freecodecamp的致敬页的测试验证不通过bug 已经写了display: block;和max-width: 100% 以及通过margin: 0 auto;居中&#xff0c;可是却通不过验证 问了通义千问 通义帮我修改后的html代码为 <!DOCTYPE html> 2<h…

打扫朋友圈

我把上周写的一篇文章&#xff0c;发到了老家的一个群里&#xff0c;结果有个多年没联系的亲戚&#xff0c;立马私信给我说&#xff0c;让我不要在群里发&#xff0c;说我写的东西不行&#xff0c;他自己看了两行就看不下去了&#xff0c;然后给我讲了一堆大道理。 哎呦我去&a…

从零开始的CPP(34)——字符串乘法

给定两个以字符串形式表示的非负整数 num1 和 num2&#xff0c;返回 num1 和 num2 的乘积&#xff0c;它们的乘积也表示为字符串形式。 注意&#xff1a;不能使用任何内置的 BigInteger 库或直接将输入转换为整数。 示例 1: 输入: num1 "2", num2 "3" …

RAG 的优化进阶与引入 Reranker

引言 在简单的 RAG 系统中&#xff0c;通过结合检索和生成技术&#xff0c;已经可以显著提升了对复杂查询的响应质量。Reranker 作为 RAG 系统中一个关键的进阶组件&#xff0c;通过对原 RAG 中检索到的内容进行重新组织&#xff0c;可以进一步提高系统的准确性。 本文将深入…

vmware虚拟机linux服务器的IP需要重启才能生效问题

vmware虚拟机linux服务器的IP需要重启才能生效问题 问题说明处理办法关闭&禁用网络管理 再次重启linux服务器&#xff0c;IP显示正常 问题说明 用vmware虚拟的linux服务器&#xff0c;配置了静态IP&#xff0c;但是每次重启liunx&#xff0c;IP都不是设置的静态IP&#xf…

国外教育人工智能发展与应用

在全球化与信息化交织的时代背景下&#xff0c;人工智能正迅速推动教育发生颠覆性变革。从大洋彼岸到东方之滨&#xff0c;世界主要国家和组织正采取相关行动和策略&#xff0c;深度挖掘和释放教育AI的潜能。本文从政策支持、教育应用两个方面&#xff0c;聚焦“教育人工智能”…

centos 安装nacos

nacos官网下载安装包&#xff08;安装nacos之前&#xff0c;先下载安装好jdk&#xff09; 概览 | Nacos 官网 2.下载好nacos压缩包之后&#xff0c;上传到linux目录中&#xff08;在/opt/目录下建好一个文件夹&#xff09; 将nacos解压 uzip nacos-server-1.4.7.zip 进入naco…

【STM32系统】基于STM32设计的按键PWM控制舵机窗帘柜子门禁家居等控制系统——文末资料下载

演示 摘要 随着智能家居技术的不断发展&#xff0c;舵机在自动化家居设备中的应用变得越来越广泛。本文设计并实现了一种基于STM32单片机的按键PWM控制舵机系统。通过按键可以精确控制舵机角度&#xff0c;实现对窗帘、柜子、门禁等家居设备的智能化控制。系统采用STM32F10x系…

C# Unity 面向对象补全计划 七大原则 之 单一职责

本文仅作学习笔记与交流&#xff0c;不作任何商业用途&#xff0c;作者能力有限&#xff0c;如有不足还请斧正 本系列作为七大原则和设计模式的进阶知识&#xff0c;看不懂没关系 1.单一职责原则&#xff08;SRP&#xff09; 单一职责原则&#xff08;Single Responsibility P…

iPhone怎么大批量删除照片:释放你的存储空间

随着iPhone相机质量的提升&#xff0c;我们越来越倾向于使用手机捕捉生活中的每一个瞬间。不久后&#xff0c;我们就会发现手机内存充满了成千上万的照片&#xff0c;这不仅占用了大量的存储空间&#xff0c;也让照片的管理变得越来越困难。对于需要释放空间的用户来说&#xf…

谷粒商城实战笔记-125-全文检索-ElasticSearch-整合-SpringBoot整合high-level-client

文章目录 一&#xff0c;技术选型1. 通过 TCP 连接&#xff08;9300 端口&#xff09;2. 通过 HTTP 连接&#xff08;9200 端口&#xff09;3.最终选择 二&#xff0c;SpringBoot整合Elasticsearch-Rest-High-Level-Client1&#xff0c;新增模块gulimall-search1&#xff0c;添…

基于python旅游推荐系统(源码+论文+部署讲解等)

博主介绍&#xff1a;✌全网粉丝10W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术栈介绍&#xff1a;我是程序员阿龙&#xff…