目录

一、先懂定位:为什么需要整数集合?(衔接哈希表)

二、整数集合的结构:像 “贴了规格标签的收纳盒”

1. encoding:收纳盒的 “规格标签”(核心:决定格子大小)

2. length:收纳盒的 “物品数量”

3. contents:收纳盒的 “有序格子”

三、核心操作:“升级”—— 从小盒子换大盒子(重点)

举个具体例子:从 int16 升级到 int32

步骤 1:换大收纳盒(扩展空间)

步骤 2:把小珠子换成大珠子(转换元素类型)

步骤 3:放进新的大珠子(添加新元素)

3.1、为什么只能升级,不能降级?(Redis 的权衡)

四、适用场景:什么时候用整数集合?(对比哈希表)

五、总结:整数集合的设计逻辑(衔接 Redis 整体哲学)


如果说 SDS 是 “智能价签”、压缩列表是 “紧凑货架”、字典是 “万能储物柜”,那整数集合(intset) 就是 Redis 为 “少量整数” 定制的分类收纳盒—— 专门用来存纯整数、数量不多的集合(比如SADD nums 10 20 30),核心优势是 “省空间、保有序、无重复”。它和哈希表(hashtable)是集合键的两种底层实现,就像收纳时 “少量小物件用分类盒,大量 / 杂物件用储物柜”。

一、先懂定位:为什么需要整数集合?(衔接哈希表)

之前学的哈希表(hashtable) 虽然能存集合(比如非整数元素SADD fruits "apple"),但有个 “内存浪费” 的问题:每个元素要存键(元素本身)和值(NULL,因为集合只需存存在性),还要处理哈希冲突。比如存 3 个小整数10、20、30,哈希表的指针、哈希槽等开销,比整数本身的空间还大。

而整数集合的思路是:用 “统一规格的数组” 存整数,不存额外指针 / 哈希信息,还保持有序无重复—— 就像用 “带格子的收纳盒” 装小珠子,每个格子只放一颗,按大小排好,没有多余的包装,省空间又好查找。

二、整数集合的结构:像 “贴了规格标签的收纳盒”

整数集合的底层是intset结构体,对应 “分类收纳盒” 的三个核心部分:规格标签、物品数量、收纳格子。我们先看结构定义,再逐个类比拆解:

typedef struct intset {uint32_t encoding;   // 收纳盒的“规格标签”(存什么类型的整数)uint32_t length;     // 收纳盒里的“物品数量”(元素个数)int8_t contents[];   // 收纳盒的“格子数组”(实际存整数的地方)
} intset;

1. encoding:收纳盒的 “规格标签”(核心:决定格子大小)

encoding就像收纳盒上贴的 “适用物品规格”,比如 “仅放直径≤5mm 的小珠子”,它决定了contents数组实际能存什么类型的整数:

  • INTSET_ENC_INT16:“小格子规格”—— 每个格子存int16_t类型(范围:-32768 ~ 32767),比如 10、20、32767。
  • INTSET_ENC_INT32:“中格子规格”—— 每个格子存int32_t类型(范围:-2147483648 ~ 2147483647),比如 32768(超过 int16 最大值)、100000。
  • INTSET_ENC_INT64:“大格子规格”—— 每个格子存int64_t类型(范围极大),比如 2147483648(超过 int32 最大值)。

关键注意:虽然contents声明是int8_t(1 字节小格子),但实际格子大小由encoding决定!就像收纳盒表面写 “小格子”,但贴的规格标签是 “中格子”,实际就能放大珠子 —— 这是 Redis 的 “灵活声明”,为了兼容不同规格。

2. length:收纳盒的 “物品数量”

length直接记录收纳盒里有多少个整数(无重复),比如存了 10、20、30,length=3。和压缩列表的zllen类似,能快速获取元素数量(O (1) 复杂度),不用数格子。

3. contents:收纳盒的 “有序格子”

contents是实际存整数的数组,有两个核心特性:

  • 有序:按从小到大排列,比如存 10、30、20,最终格子里是[10,20,30]—— 方便快速查找(用二分法,O (logN) 复杂度)。
  • 无重复:同一个整数不会出现两次,比如再存 20,Redis 会检查格子里已有,不重复添加 —— 就像收纳盒里不会有两颗一样大的珠子。

三、核心操作:“升级”—— 从小盒子换大盒子(重点)

整数集合最特殊的逻辑是 “自动升级”:当要放的整数 “太大”(超过当前encoding的范围),就必须把整个收纳盒换成更大规格,再统一转换原有元素的 “大小”,最后放进新元素。这就像 “小珠子收纳盒里要放大珠子,必须先换大盒子,把原来的小珠子都换成大珠子,再放大珠子”。

举个具体例子:从 int16 升级到 int32

假设现在有个 “小格子收纳盒”(encoding=INTSET_ENC_INT16),已经放了两个小整数:10、32767(int16 的最大值)。现在要放 32768(超过 int16 的最大值,必须用 int32),升级步骤对应生活场景:

步骤 1:换大收纳盒(扩展空间)
  • 原来的小盒子:每个格子占 2 字节(int16),2 个元素共 4 字节。
  • 新的大盒子:每个格子占 4 字节(int32),需要存 3 个元素(原有 2 个 + 新 1 个),总空间 = 3×4=12 字节。
  • Redis 会申请 12 字节的新空间,代替原来的 4 字节 —— 就像把 2 格的小盒子,换成 3 格的大盒子。
步骤 2:把小珠子换成大珠子(转换元素类型)
  • 不能直接把小珠子(int16 的 10、32767)放进大格子,必须先 “放大” 成大珠子(int32 的 10、32767)。
  • 转换时要保持顺序:原来小盒子里是[10,32767],转换后大盒子的前两格还是[10,32767](只是每个占 4 字节)—— 就像把小珠子装进大托里,位置不变。
步骤 3:放进新的大珠子(添加新元素)
  • 把 32768(int32 类型)放进大盒子的最后一格,最终格子里是[10,32767,32768],保持有序。
  • 最后更新encoding为 INTSET_ENC_INT32,length为 3—— 收纳盒的规格标签和数量标签同步更新。

3.1、为什么只能升级,不能降级?(Redis 的权衡)

升级后就算删了 “大珠子”(比如把 32768 删掉,只剩 10、32767),Redis 也不会把大盒子换回小盒子 —— 这就是 “无降级” 规则,原因很简单:

  1. 麻烦且没必要:降级需要先检查所有元素是否都符合小规格,再转换类型、缩小空间 —— 就像把大珠子换回小珠子,再换小盒子,步骤多,浪费时间。
  2. 效率优先:Redis 认为 “少量内存浪费” 比 “频繁降级的性能损耗” 更划算。比如大盒子里放小珠子,多占的内存不多(每个元素多 2 字节),但省去了降级的麻烦。
  3. 避免风险:如果降级后又要放大珠子,得再次升级,反复操作反而更慢 —— 就像换了小盒子又要换大的,不如一直用大的。

四、适用场景:什么时候用整数集合?(对比哈希表)

Redis 选择整数集合还是哈希表,遵循 “整数优先、少量优先” 的原则,和压缩列表的 “小数据优先” 思路一致:

集合类型底层实现原因(生活类比)
纯整数元素 + 元素少(默认<512 个)整数集合分类收纳盒存少量小珠子,省空间、好排序
非整数元素(如字符串)哈希表万能储物柜存杂物件,不管类型,查找快
纯整数元素 + 元素多哈希表收纳盒格子太多不好翻,储物柜(哈希表)更快

举例:

SADD nums 1 2 3(纯整数、少元素)→ 整数集合;

SADD fruits "apple" "banana"(非整数)→ 哈希表;

SADD big_nums 1 2 ... 1000(多元素)→ 哈希表。

五、总结:整数集合的设计逻辑(衔接 Redis 整体哲学)

整数集合的所有设计,都和之前学的 SDS、压缩列表、跳跃表一脉相承,体现 Redis“因地制宜、权衡取舍” 的核心思路:

  • SDS:用 “len+free” 平衡 “字符串扩展” 和 “内存浪费”—— 取舍:预分配少量空间换扩展效率;
  • 压缩列表:用 “连续内存 + 可变标签” 平衡 “内存节省” 和 “连锁更新风险”—— 取舍:接受罕见更新换极致省内存;
  • 整数集合:用 “统一规格数组 + 自动升级” 平衡 “内存节省” 和 “类型兼容”—— 取舍:不支持降级换操作简单、效率高。

简单说,整数集合就是 Redis 为 “少量整数集合” 量身定制的 “高效收纳盒”:它没有哈希表的灵活,但胜在省空间、有序;没有压缩列表的复杂,胜在操作简单、只存整数。这种 “专物专用” 的设计,正是 Redis 能兼顾性能和内存的关键。

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

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

相关文章

Linux 进程状态 — 僵尸进程

🎁个人主页:工藤新一 🔍系列专栏:C面向对象(类和对象篇) 🌟心中的天空之城,终会照亮我前方的路 🎉欢迎大家点赞👍评论📝收藏⭐文章 文章目录进…

React 中 key 的作用

React 中 key 的作用是什么? Date: August 31, 2025 Area: 原理key 概念 在 React 中,key 用于识别哪些元素是变化、添加或删除的。 在列表渲染中,key 尤其重要,因为它能提高渲染性能和确保组件状态的一致性。key 的作用 1&#x…

wpf之附加属性

前言 附加属性是 WPF 中一个非常强大和独特的概念。简单来说,它允许一个对象为另一个在其本身类定义中未定义的属性赋值。 1、定义附加属性 定义一个Watermark的附加属性,该属性的作用是将TextBox的附加属性改变时,TextBox的字体颜色改成灰…

深入浅出 RabbitMQ-消息可靠性投递

大家好,我是工藤学编程 🦉一个正在努力学习的小博主,期待你的关注实战代码系列最新文章😉C实现图书管理系统(Qt C GUI界面版)SpringBoot实战系列🐷【SpringBoot实战系列】SpringBoot3.X 整合 Mi…

数字化时代,中小企业如何落地数字化转型

大数据时代,各行各业的行业龙头和大型集团都已经开始了数据管理,让数据成为数据资产。但是在我国,中小企业的数量巨大,很多管理者忽视了这一点,今天我们就来聊一聊中小企业的数字化转型。中小企业需要数字化转型首先要…

Unity笔记(九)——画线功能Linerenderer、范围检测、射线检测

写在前面:写本系列(自用)的目的是回顾已经学过的知识、记录新学习的知识或是记录心得理解,方便自己以后快速复习,减少遗忘。这里只记录代码知识。十一、画线功能Linerenderer画线功能Linerenderer是Unity提供的画线脚本,创建一个空…

刷题记录(8)string类操作使用

一、仅反转字母 917. 仅仅反转字母 - 力扣(LeetCode) 简单来说输入字符串,要求你返回所有仅字母位置反转后的字符串。 简单看一个样例加深理解: 前后互换,我想思路基本很明显了,双指针,或者说…

用好AI,从提示词工程到上下文工程

前言 随着 AI 大模型的爆发,提示词工程(prompt engineering ) 一度是用户应用 AI ,发挥 AI 能力最重要、也最应该掌握的技术。 但现在,在 “提示词工程”的基础上,一个更宽泛也更强力的演化概念被提出,也就是本文我们要介绍的 “上下文工程(Context Engineering)” …

计算机Python毕业设计推荐:基于Django+Vue用户评论挖掘旅游系统

精彩专栏推荐订阅:在下方主页👇🏻👇🏻👇🏻👇🏻 💖🔥作者主页:计算机毕设木哥🔥 💖 文章目录 一、项目介绍二、…

⸢ 肆 ⸥ ⤳ 默认安全:安全建设方案 ➭ a.信息安全基线

👍点「赞」📌收「藏」👀关「注」💬评「论」 在金融科技深度融合的背景下,信息安全已从单纯的技术攻防扩展至架构、合规、流程与创新的系统工程。作为一名从业十多年的老兵,将系统阐述数字银行安全体系的建设…

如何用AI视频增强清晰度软件解决画质模糊问题

在视频制作和分享过程中,画质模糊、细节丢失等问题常常影响观看体验。无论是老旧视频的修复还是低分辨率素材的优化,清晰度提升都成为用户关注的重点。借助专业的AI技术,这些问题可以得到有效解决。目前市面上存在多种解决方案,能…

Linux92 shell:倒计时,用户分类

问题 while IFS read -r line;doootweb kk]# tail -6 /etc/passwd user1r4:x:1040:1040::/home/user1r4:/bin/bash useros20:x:1041:1041::/home/useros20:/bin/bash useros21:x:1042:1042::/home/useros21:/bin/bash useros22:x:1043:1043::/home/useros22:/bin/bash useros23…

LinkedList源码解析

1. 数据结构设计 (1) 节点结构 LinkedList 的核心是双向链表节点 Node&#xff1a; private static class Node<E> {E item; // 存储的元素Node<E> next; // 后继节点Node<E> prev; // 前驱节点Node(Node<E> prev, E element, Node<E&g…

语雀批量导出知识库

使用工具&#xff1a;yuque-dl 参考文档&#xff1a; GitHub - gxr404/yuque-dl: yuque 语雀知识库下载 Yuque-DL&#xff1a;一款强大的语雀资源下载工具_语雀文档怎么下载-CSDN博客

电子电气架构 --- 当前企业EEA现状(下)

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

flink中的窗口的介绍

本文重点 无界流会源源不断的产生数据,有的时候我们需要把无界流进行切分成一段一段的有界数据,把一段内的所有数据看成一个整体进行聚合计算,这是实现无界流转成有界流的方式之一。 为什么需要窗口 数据是源源不断产生的,我们可能只关心某个周期内的统计结果。比如电费…

自建es 通过Flink同步mysql数据 Docker Compose

资源es:7.18 kibana:7.18 flink:1.17.2目录mkdir -p /usr/project/flink/{conf,job,logs} chmod -R 777 /usr/project/flink #资源情况 mysql8.0 Elasticsearch7.18 自建# 目录结构 /usr/project/flink/ /usr/project/flink/ ├── conf/ │ ├── flink-conf.yaml │ └…

AI浏览器和钉钉ONE是不是伪需求?

最近两则新闻格外引起了我的注意&#xff1a;一是Claude推出了官方浏览器插件&#xff0c;二是钉钉发布了钉钉ONE。前者说明AI浏览器未必有必要&#xff0c;后者则描绘了一幅“刷刷手机就能完成工作”的未来办公图景。这几天我经常在思考&#xff0c;AI浏览器是不是没有必要&am…

从结构化到多模态:RAG文档解析工具选型全指南

在RAG系统建设中&#xff0c;文档解析质量直接决定最终效果上限&#xff0c;选择合适的解析工具已成为避免"垃圾进&#xff0c;垃圾出"&#xff08;GIGO&#xff09;困境的关键决策。一、文档解析&#xff1a;RAG系统的基石与瓶颈 当前企业知识库中超过80%的信息存储…

设计模式:享元模式(Flyweight Pattern)

文章目录一、享元模式的介绍二、实例分析三、示例代码一、享元模式的介绍 享元模式&#xff08;Flyweight Pattern&#xff09; 是一种结构型设计模式。通过共享相同对象&#xff0c;减少内存消耗&#xff0c;提高性能。 它摒弃了在每个对象中保存所有数据的方式&#xff0c; 通…