6、Redis系统-数据结构-02-链表

二、List(列表)

1、List 数据结构的必要性

List 是一种有序的数据结构,可以按顺序存储多个字符串。它的主要特点如下:

  1. 有序性:List 中的元素是有序的,可以通过索引访问。
  2. 双向操作:List 支持从两端进行操作(如插入和删除),非常灵活。
  3. 多用途:List 可以用作队列(FIFO)和栈(LIFO),适用于多种场景。

在实际应用中,List 非常适合用于需要保持顺序的数据存储,例如任务队列、聊天记录、时间线等。由于 Redis 的高性能特点,List 还可以处理大量的数据读写操作。

2、List 的底层实现

在 Redis 中,List 有两种底层实现方式:

  1. 压缩列表(ziplist)
  2. 快速列表(quicklist)
2.1 压缩列表(ziplist)

压缩列表是一种为节省内存而设计的紧凑型双向链表。它通过将多个元素压缩存储在一个连续的内存块中,减少了内存碎片,提高了内存利用率。

结构:

typedef struct {uint32_t zlbytes;    // ziplist 占用的总字节数uint32_t zltail;     // ziplist 表尾节点的偏移量uint16_t zlen;       // ziplist 中节点的数量unsigned char entries[];  // 数据项
} ziplist;

每个数据项(entry)包含:

  • prevrawlen:前一个数据项的长度
  • len:当前数据项的长度
  • data:实际存储的数据

压缩列表通过紧凑的内存布局来节省空间,非常适合存储少量数据或小数据量的场景。然而,由于压缩列表的连续内存结构,在插入和删除操作时需要移动大量数据,时间复杂度较高。

2.2 快速列表(quicklist)

为了弥补压缩列表在插入和删除操作上的不足,Redis 3.2 引入了快速列表(quicklist)。快速列表结合了压缩列表和双向链表的优点,是一种用于实现列表(List)类型的高效数据结构。每个快速列表节点(quicklistNode)包含一个压缩列表,实现了数据的紧凑存储和高效操作。

结构:

typedef struct quicklist {quicklistNode *head;      // 快速列表头节点quicklistNode *tail;      // 快速列表尾节点unsigned long count;      // 快速列表中的节点数量unsigned long len;        // 快速列表中的元素数量int fill : QL_FILL_BITS;  // 填充因子unsigned int compress : QL_COMP_BITS;  // 压缩深度quicklistBookmark bookmarks[];  // 书签
} quicklist;typedef struct quicklistNode {struct quicklistNode *prev;   // 前一个节点struct quicklistNode *next;   // 后一个节点unsigned char *zl;            // 压缩列表unsigned int sz;              // 压缩列表大小unsigned int count : 16;      // 节点中元素数量unsigned int encoding : 2;    // 编码类型unsigned int container : 2;   // 容器类型unsigned int recompress : 1;  // 重新压缩标志unsigned int attempted_compress : 1;  // 尝试压缩标志unsigned int extra : 10;      // 额外空间
} quicklistNode;

快速列表通过将多个压缩列表节点(quicklistNode)连接成一个双向链表,使得在两端进行插入和删除操作非常高效。同时,压缩列表的紧凑存储方式也能保证较高的内存利用率。

3、List 的常用操作

Redis 提供了丰富的 List 操作命令,包括插入、删除、获取和修剪等操作。

插入操作
  • LPUSH key value [value ...]:在列表的左端插入一个或多个值。该命令会将一个或多个值插入到列表的左端(头部)。
  • RPUSH key value [value ...]:在列表的右端插入一个或多个值。该命令会将一个或多个值插入到列表的右端(尾部)。
删除操作
  • LPOP key:移除并返回列表的左端元素。该命令会移除并返回列表头部的元素。
  • RPOP key:移除并返回列表的右端元素。该命令会移除并返回列表尾部的元素。
获取操作
  • LINDEX key index:获取列表中指定索引的元素。该命令会返回列表中指定索引的元素。
  • LRANGE key start stop:获取列表中指定范围的元素。该命令会返回指定范围内的元素,start 和 stop 为索引。
修剪操作
  • LTRIM key start stop:对列表进行修剪,只保留指定范围内的元素。该命令会将列表修剪到指定范围之外的元素都会被删除。
4、List 的实现细节

创建 List 对象

robj *createQuicklistObject(void) {quicklist *l = quicklistCreate();robj *o = createObject(OBJ_LIST, l);o->encoding = OBJ_ENCODING_QUICKLIST;return o;
}

创建 quicklist 对象

quicklist *quicklistCreate(void) {struct quicklist *quicklist;quicklist = zmalloc(sizeof(*quicklist));quicklist->head = quicklist->tail = NULL;quicklist->len = 0;quicklist->count = 0;quicklist->compress = 0;quicklist->fill = -2;  // 默认填充因子quicklist->bookmark_count = 0;return quicklist;
}

创建 quicklistNode 对象

quicklistNode *quicklistCreateNode(void) {quicklistNode *node;node = zmalloc(sizeof(*node));node->prev = node->next = NULL;node->zl = NULL;node->sz = 0;node->count = 0;node->encoding = 0;node->container = 0;node->recompress = 0;node->attempted_compress = 0;node->extra = 0;return node;
}

压缩列表与快速列表的结合

// 创建一个新的 quicklist 对象
quicklist *quicklist = quicklistCreate();// 创建一个新的 quicklistNode 对象
quicklistNode *node = quicklistCreateNode();// 为 quicklistNode 分配一个新的压缩列表
node->zl = ziplistNew();
node->sz = ziplistBlobLen(node->zl);// 将 node 插入到 quicklist 中
quicklist->head = node;
quicklist->tail = node;
quicklist->len = 1;
quicklist->count = ziplistLen(node->zl);
5、使用示例

以下是一些使用 Redis List 的示例,展示了如何利用 List 进行数据的存储和操作。

插入数据

LPUSH mylist "world"
# (integer) 1LPUSH mylist "hello"
# (integer) 2

获取数据

LRANGE mylist 0 -1
# 1) "hello"
# 2) "world"

删除数据

LPOP mylist
# "hello"LRANGE mylist 0 -1
# 1) "world"
结论

通过上述解析,我们可以更好地理解 List 的设计思想和实现原理,从而在实际开发中更好地利用 List 提供的优势。在 Redis 中,List 通过压缩列表和快速列表的结合,实现了高效的存储和操作,适用于多种场景如队列、栈和消息列表等。了解这些优化策略,可以帮助我们在实际应用中更好地利用 Redis 的性能和功能。

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

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

相关文章

JavaWeb系列二十二: 线程数据共享和安全(ThreadLocal)

韩顺平-线程数据共享和安全ThreadLocal 什么是ThreadLocal?ThreadLocal环境搭建ThreadLocal快速入门ThreadLocal源码阅读threadLocal.set()源码threadLocal.get()源码 什么是ThreadLocal? ThreadLocal的作用: 可以实现在同一个线程数据共享, 从而解决多线程数据安全问题.Thr…

小阿轩yx-Haproxy搭建Web群集

小阿轩yx-Haproxy搭建Web群集 Haproxy 简介 提供高可用性 能做出标准的负载均衡 支持虚拟主机 具备健康检查能力 能用于各式各样的代理 轻量级代理环境 解决方案优势 免费 快速 可靠 特性 特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或…

前端面试题24(css3)

下面是一些常见的 CSS3 面试题,这些问题可以帮助你评估应聘者对 CSS3 的掌握程度: 1. 解释 CSS3 中的动画关键帧(keyframes)和它们是如何工作的? 回答要点:keyframes 规则用于创建动画,它可以…

软件仓库及第三方软件仓库

一、本地软件仓库的搭建: 建立挂载目录: [rootlocalhost ~]# mkdir /rhel9 挂载镜像到/rhel9目录中 [rootlocalhost ~]# mount /dev/sr1 /rhel9/ mount: /rhel9: WARNING: source write-protected, mounted read-only. [rootlocalhost ~]# ls /rhel9/ A…

后端之路——文件本地上传

一、基础原理 文件上传是一个很基础的知识点&#xff0c;尤其是本地上传&#xff0c;在现实开发基本都是云上传&#xff0c;但是作为一个基础要简单了解一下 首先前端我就不多讲解了&#xff0c;网页开发里用<form>表单可以上传文件&#xff0c;只需要加上这三属性&…

pytest系列——pytest_runtest_makereport钩子函数获取测试用例执行结果

前言 pytest测试框架提供的很多钩子函数方便我们对测试框架进行二次开发&#xff0c;可以根据自己的需求进行改造。 例如&#xff1a;钩子方法&#xff1a;pytest_runtest_makereport &#xff0c;可以更清晰的了解测试用例的执行过程&#xff0c;并获取到每个测试用例的执行…

element Input 输入框 输入长度限制 maxlength=“10“默认输入长度提示颜色为红色

对于el-input&#xff0c;直接显示输入长度提示并上色并不直接支持&#xff0c;但我们可以用一些技巧来模拟这一效果。而对于el-textarea&#xff0c;虽然它没有直接的计数提示&#xff0c;但可以通过类似的技巧添加。 对于el-input <template><div class"inpu…

【AI原理解析】—线性回归原理

目录 一、定义与基本假设 二、参数估计 三、模型评估 四、假设检验 五、线性回归的变种 一、定义与基本假设 定义&#xff1a; 线性回归是一种通过建立一个或多个自变量&#xff08;解释变量&#xff09;与因变量&#xff08;响应变量&#xff09;之间的线性关系模型&…

(译文)IRIG-B对时编码快速入门

原文 PDF&#xff1a;https://ww1.microchip.com/downloads/aemDocuments/documents/FTD/tekron/tekronwhitepapers/221223-A-guide-to-IRIG-B.pdf IRIG-B3 概论 Inter-Range Instrument Group 时间码&#xff08;简称IRIG&#xff09;是一系列标准时间码格式。用于将时间信…

使用Cloudflare免费开启全站https配置SSL证书

HTTPS 我的服务器和域名是在华为云&#xff0c;华为云SSL证书巨贵&#xff0c;通过Cloudflare可以将自己的网站免费设置成https。 Cloudflare注册 访问Cloudflare, 注册账号。 添加站点 添加你自己的站点&#xff0c;选择免费的套餐。 添加DNS 添加你的域名、子域名、…

PCB阻抗控制为何如此重要?

或许你在各个厂商打PCB板的时候&#xff0c;会遇到询问你是否需要阻抗的的下单需求&#xff1f; 在当今的应用中&#xff0c;设计通常变得越来越快&#xff0c;控制布局参数比以往任何时候都更加重要。 在PCB设计和生产过程中&#xff0c;有几种方法可以进行阻抗控制。最常见的…

轻松转换!两款AI工具让word秒变ppt!

想把Word文档一键生成PPT&#xff0c;过去有一个很常见的做法&#xff1a;先在Word文档中设置标题样式&#xff0c;通过标题样式来分隔每一部分&#xff0c;之后导出为PPT&#xff0c;就能得到一份PPT的雏形&#xff0c;但这种方法无法对PPT自动进行美化&#xff0c;即得到的只…

ZGC在三色指针中的应用

ZGC基于颜色指针的并发处理算法 ZGC初始化之后&#xff0c;整个内存空间的地址视图被设置为Remapped&#xff0c;当进入标记阶段时的视图转变为Marked0&#xff08;也称为M0&#xff09;或者Marked1&#xff08;也称为M1&#xff09;&#xff0c;从标记阶段结束进入转移阶段时…

计算机学生在大学四年应是以数据结构和算法为重还是技术为重?

我给你说点比较实在的吧&#xff0c;不管你是不是计算机专业科班出身的大学生&#xff0c;不管你在不在本科大学&#xff0c;不管你的出身和背景如何&#xff0c;想要走上计算机工作岗位&#xff0c;那必须得有拿得出手的一技之长&#xff0c;这个行业是靠技术吃饭的。 刚好我有…

Kotlin算法:把一个整数向上取值为最接近的2的幂指数值

Kotlin算法&#xff1a;把一个整数向上取值为最接近的2的幂指数值 import kotlin.math.ln import kotlin.math.powfun main(args: Array<String>) {val number intArrayOf(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18)number.forEach {println("$…

一.1 信息就是位+上下文

hello程序的生命周期是从一个源程序&#xff08;或者说源文件&#xff09;开始的&#xff0c;即程序员通过编辑器创建并保存的文本文件&#xff0c;文件名是hello.c。源程序实际上就是一个由0和1组成的位&#xff08;又称为比特&#xff09;序列&#xff0c;8个位被组织成一组&…

python读取指定文件夹下的图片(glob获取)

python读取指定文件夹下的图片&#xff08;glob获取&#xff09; 定义traverse_images函数&#xff0c;仅需要改变下根路径即可 glob是python中用来查找符合特定规则的文件路径名的函数 import os from glob import globdef traverse_images (folder_path):image_formats …

leetcode秋招冲刺 (专题16--18)

专题16&#xff1a;分治 题目169&#xff1a;多数元素&#xff08;YES&#xff09; 解题思路&#xff1a;使用哈希表可以统计出现次数的性质&#xff0c;直接统计就行。 给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊…

ESIX配置备份和恢复

ESIX虽然重装很快&#xff0c;但是原本配置就丢失了&#xff0c;在硬件不变的情况下&#xff0c;可以使用配置备份和配置恢复的方法。 1、备份配置 1.1、执行以下两条命令 vim-cmd hostsvc/firmware/sync_configvim-cmd hostsvc/firmware/backup_config如下图&#xff0c;只需…

2024年江苏省研究生数学建模科研创新实践大赛赛题分享-B题

火箭烟幕弹运用策略优化 随着光电技术的发展&#xff0c;现代战争中光电制导对战场重要目标的生存构成了极大威胁。而烟幕在对抗红外制导、激光制导、毫米波探测等光电武器方面具有显著成效。烟幕主要由固体和液体微粒混合而成&#xff0c;它通过散射或吸收的方式&#xff0c;干…