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) 1

LPUSH 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.mfbz.cn/a/783441.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【VUE基础】VUE3第一节—vite创建vue3工程

什么是VUE Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界面&#xff0…

MySQL性能优化 一、系统配置优化

数据库优化纬度有四个&#xff1a; 硬件升级、系统配置、表结构设计、SQL语句及索引。 优化选择&#xff1a; 优化成本&#xff1a;硬件升级 > 系统配置 > 表结构设计 > SQL语句及索引优化效果&#xff1a;硬件升级 < 系统配置 < 标结果设计 < SQL语句及索…

【C++】———— 继承

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;C 创作时间 &#xff1a;2024年7月5日 一、什么是继承&#xff1f; 继承的概念 定义&#xff1a; 继承机制就是面向对象设计中使代码可以复用的重要手段&#xff0c;它允许在程序员保持原有类特性的基础上进行扩展…

[工具教程]-31-解决mac扣盖后电池耗电快(谁在偷偷的用电池)

查看耗电模式 $ pmset -g查看 hibernatemode 这一行&#xff0c;如果 hibernatemode 后面的数字是 0 &#xff0c;那这种休眠模式下&#xff0c;掉电程度就是非常严重&#xff0c;如果 hibernatemode 后面的数字是 3 &#xff08;大部分人的电脑应该是这个休眠模式&#xff09…

LabVIEW中自定义Ring控件的图标

在LabVIEW中&#xff0c;自定义Ring控件的图标可以让用户界面更加直观和友好。以下是如何在LabVIEW中自定义Ring控件的图标的详细步骤&#xff1a; 步骤1&#xff1a;创建或获取图标 首先&#xff0c;你需要创建或获取你想要在Ring控件中使用的图标。你可以使用图像编辑软件&…

springboot+vue+mybatis图书销售管理系统+PPT+论文+讲解+售后

在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括图书销售管理系统的网络应用&#xff0c;在外国图书销售管理系统已经是很普遍的方式&#xff0c;不过国内的管理网站可能还处于起步阶段。图书销售管理系统具有网上图书信息管…

BaseServlet的封装

创建BaseServlet的必要性 如果不创建BaseServlet&#xff0c;现在我们只要实现一个功能&#xff0c;我们就需要创建一个servlet! 例如:用户模块(登录&#xff0c;注册&#xff0c;退出录&#xff0c;激活&#xff0c;发送邮件等等功能) 也就是说&#xff0c;我们必须要创建一…

ASO优化不仅仅是苹果商店,安卓商店同样不可忽视

大家一谈起ASO优化&#xff0c;不少人反应大多数都是IOS市场的优化&#xff0c;其实安卓也是不可分割的大市场&#xff0c;在国内手机应用市场&#xff0c;安卓的用户质量在稳步提高&#xff0c;因此开发者也越来越重视安卓市场的推广。做好安卓ASO也是非常必要的。 一、安卓市…

音视频质量评判标准

一、实时通信延时指标 通过图中表格可以看到&#xff0c;如果端到端延迟在200ms以内&#xff0c;说明整个通话是优质的&#xff0c;通话效果就像大家在同一个房间里聊天一样&#xff1b;300ms以内&#xff0c;大多数人很满意&#xff0c;400ms以内&#xff0c;有小部分人可以感…

五行、八卦、天干、地支

零基础入门&#xff1a;五行、八卦、天干、地支 给她家推荐一个小程序&#xff0c;感觉挺准的&#xff01;

PTrade常见问题系列5

回测失败&#xff1a;可用资源不足。 回测运行失败&#xff0c;错误码&#xff1a;2 错误信息&#xff1a;可用资源不足&#xff0c;请稍后在创建。 1、之前客户未限制客户容器使用内存和CPU&#xff0c;周末修改配置&#xff0c;限制了内存和CPU&#xff1b; 2、此报错是用户…

51-3 内网信息收集 - 获取RDP密码信息(没有实验成功)

获取常见应用软件凭据 注意: %USERPROFILE% 是环境变量。在使用系统权限时,可以将 %USERPROFILE% 替换为绝对路径,或使用其他用户的令牌进行操作。 获取 RDP 保存的凭据(远程桌面) 为了避免每次连接服务器都进行身份验证,经常使用 RDP 远程桌面连接远程服务器的用户可能…

STM32蓝牙HID实战:打造低功耗、高性能的客制化键盘

一、项目概述 本项目旨在使用STM32单片机打造一款功能强大的蓝牙客制化键盘&#xff0c;它拥有以下特点&#xff1a; 九键布局&#xff0c;小巧便携: 满足日常使用需求&#xff0c;方便携带。全键可编程: 所有按键和旋钮均可通过电脑软件自定义快捷键&#xff0c;实现个性化功…

融资融券两融技巧,开通条件和费用详情4%

融资融券费用 融资融券有两项费用&#xff0c;分别是利息和交易佣金。一般情况下融资年息是5%&#xff0c;融券年息是9.35%&#xff0c;目前有极少数一部分券商能够做到4.5%&#xff0c;融资20万一天只需要25元。 然后咱们再看看交易佣金&#xff0c;目前市面上万分之3到千分…

【基于R语言群体遗传学】-12-超显性与次显性

欢迎先看前面的博客&#xff0c;再继续进行后面的内容&#xff1a; 群体遗传学_tRNA做科研的博客-CSDN博客 当杂合子的适应度超出纯合子的范围时&#xff0c;二倍体能够展现出更多令人着迷的选择实例。这种形式的一种是杂合子优势&#xff0c;或称为“超显性”&#xff0c;其…

(三)前端javascript中的数据结构之链表上

在js中&#xff0c;没有为我们提供原生的数据结构支持的&#xff0c;但是在java中是有提供的。所以需要我们去模拟这种结构实现。 链表中最关键的一个元素&#xff0c;就是头节点&#xff0c;头节点不存储数据&#xff0c;指向第一个节点链表中几乎所有的操作都要从头结点开始。…

数字流的秩

题目链接 数字流的秩 题目描述 注意点 x < 50000 解答思路 可以使用二叉搜索树存储出现的次数以及数字的出现次数&#xff0c;方便后续统计数字x的秩关键在于构建树的过程&#xff0c;如果树中已经有值为x的节点&#xff0c;需要将该节点对应的数字出现次数加1&#xf…

味全财税数字化实践分享,百望云助力实现数电票管理能力升级!

随着金税四期的启动&#xff0c;数电票全面落地应用&#xff0c;这不仅大幅提高了发票处理效率&#xff0c;更重塑了企业的财务管理流程&#xff0c;为企业财务数字化转型指明了新的方向。 杭州味全食品有限公司&#xff08;以下简称“味全”&#xff09;正在推进财税数字化建设…

(2024,稀疏 MoE,大量小专家,参数高效专家检索 PEER,product key 检索)混合百万专家

Mixture of A Million Experts 公和众与号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 1. 简介 2. 方法 3. 实验 0. 摘要 标准 Transformer 架构中的前馈&#xff08;feedforward&a…

轻松集成,高效变现:Flat Ads SDK助力开发者轻松跨越广告变现门槛

在当今的移动应用开发领域,广告变现是开发者们普遍关注的重要话题。如何在不影响用户体验的前提下,最大化地实现广告收益,成为了许多开发者面临的挑战。为此,Flat Ads SDK 应运而生,它以“轻松集成,合规守护,高效变现”为核心理念,帮助开发者轻松解决流量变现难题。 一、高效变…