15- Redis 中的 整数集合 数据结构

整数集合是 Set 对象的底层实现之一。当一个 Set 对象只包含整数值元素,并且元素数量不大时,就会使用整数集合这个数据结构作为底层实现。

1. 整数集合结构设计

整数集合本质上是一块连续内存空间,它的结构定义如下:

typedef struct intset {// 编码方式uint32_t encoding;// 集合包含的元素数量uint32_t length;// 保存元素的数组int8_t contents[];
} intset;

可以看到,保存元素的容器是一个 contents 数组,虽然 contents 被生命为 int8_t 类型的数组,但是实际上 contents 数组并不保存任何 int8_t 类型的元素,contents 数组的真正类型取决于 intset 结构体里的 encoding 属性的值。比如:

  • 如果 encoding 属性值为 INTSET_ENC_INT16,那么 contents 就是一个 int16_t 类型的数组,数组中每一个元素的类型都是 int16_t;

  • 如果 encoding 属性值为 INTSET_ENC_INT32,那么 contents 就是一个 int32_t 类型的数组,数组中每一个元素的类型都是 int32_t;

  • 如果 encoding 属性值为 INTSET_ENC_INT64,那么 contents 就是一个 int64_t 类型的数组,数组中每一个元素的类型都是 int64_t;

不同类型的 contents 数组,意味着数组的大小也会不同。

2. 整数集合的升级操作

整数集合会有一个升级规则,就是当我们将一个新元素加入到整数集合里面,如果新元素的类型(int32_t)比整数集合现有所有元素的类型(int16_t)都要长时,整数集合需要先进行升级,也就是按新元素的类型(int32_t)扩展 contents 数组的空间大小,然后才能将新元素加入到整数集合里,当然升级的过程中,也要维持整数集合的有序性。

为什么管理混合类型会增加复杂度:

从计算机的基本原理来看,int16_tint32_t 在内存中的占用大小、表达范围以及在某些情况下的处理方式上存在区别,这些区别导致了在处理它们时的一些差异。在数据结构内部同时管理 int16_tint32_t 类型的数据,意味着每次操作数据(如添加、删除、查找)时,都需要判断并根据不同的类型作相应处理。这不仅在编码时增加了分支判断的复杂度,还可能导致在执行时增加额外的判断开销。此外,混合类型的数据存储可能导致内存布局的非连续性和对齐问题,进而影响访问效率。

因此,虽然 int16_tint32_t 在概念上是相似的(都是用来存储整数的类型),但它们在内存占用、表达范围和处理细节上的这些区别,决定了在统一的数据结构中同时管理这些不同类型会使得结构管理变得更加复杂。Redis 的整数集合通过类型升级来避免这种复杂性,从而使得数据存储、访问和维护更加高效和一致。

整数集合升级的过程不会重新分配一个新类型的数组,而是在原本的数组上扩展空间,然后再将每个元素按间隔类型大小分割,如果 encoding 属性值为 INTSET_ENC_INT16,则每个元素的间隔就是 16 位。

举个例子,假设有一个整数集合里有 3 个类型为 int16_t 的元素。

现在,往这个整数集合中加入一个新元素 65535,这个新元素需要用 int32_t 类型来保存,所以整数集合要进行升级操作,首先需要为 contents 数组扩容,在原本空间的大小上再扩容多 80 位(4 × 32 - 3 × 16 = 80),这样就能保存下四个类型为 int32_t 的元素

扩容完 contents 数组空间大小后,需要将之前的三个元素转换为 int32_t 类型,并将转换后的元素放置到正确的位上面,并且需要维持底层数组的有序性不变,整个转换过程如下:

整数集合升级有什么好处呢?

如果要让一个数组同时保存 int16_t、int32_t、int64_t 类型的元素,最简单的做法就是直接使用 int64_t 类型的数组。不过这样的话,当如果元素都是 int16_t 类型的,就会造成内存浪费的情况。

整数集合升级就能避免这种情况,如果一直向整数集合添加 int16_t 类型的元素,那么整数集合的底层实现就一直是用 int16_t 类型的数组,只有在我们要将 int32_t 类型或 int64_t 类型的元素添加到集合时,才会对数组进行升级操作。

因此,整数集合升级的好处是节省内存资源

整数集合支持降级操作吗?

不支持降级操作,一旦对数组进行了升级,就会一直保持升级后的状态。比如前面的升级操作的例子,如果删除了 65535 元素,整数集合的数组还是 int32_t 类型的,并不会因此降级为 int16_t 类型。

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

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

相关文章

Chrome DevTools 使用攻略

Chrome DevTools是谷歌浏览器提供的一套强大的开发工具,对于前端开发人员来说是不可或缺的利器。下面将从多个方面介绍Chrome DevTools的使用攻略: 一、启动方式 通过快捷键: 在Windows/Linux上,按下 F12、Ctrl Shift I 或 C…

集成学习笔记

集成学习 简介 决策树 GBDT 拟合残差 一般 GBDT XGBOOST 弓 1 能表达样本落入的子节点,但是不能把表示结构 2 3.正则项 – 惩罚 防止过拟合,比如一个值总共有10颗树都是由同一颗树决定的,过拟合 5 找到一种方式不依赖于损失函数 …

Android开发之内访Sqlite数据库(六)

文章目录 1. Android开发之外访Sqlite数据库1.1 Sqlite数据库的优点1.2 Sqlite接口简介接口中的抽象方法接口中的实例方法接口的构造方法示例步骤例子 —— 实现增删改查 1. Android开发之外访Sqlite数据库 SQLite是一个软件库,实现了自给自足的、无服务器的、零配…

python的优势有哪些?

python的优点很多,下面简单地列举一些: 简单 Python的语法非常优雅,甚至没有像其他语言的大括号,分号等特殊符号,代表了一种极简主义的设计思想。阅读Python程序像是在读英语。 易学 Python入手非常快,学习…

K8s:无状态

无状态服务 无状态服务是指服务的实例之间没有持久化状态,每个实例都是相同的,可以互换使用。 调度器 ReplicationController 简称 RC是 Kubernetes 早期版本中用来确保 Pod 副本始终运行的 API 对象。它通过监控 Pod 副本的数量,确保任何…

vue 常用的 UI 框架及表格

vue 3 常用的 UI 框架及表格 常用 UI 框架 Element PlusAnt Design VueiViewVxe UIVuetifyBootstrap VueMuse UI 专业表格 SpreadJSAG GridVxe Table

Linux——内存管理代码分析

虚空间管理 页框和页的关系 页框 将内存空间分为一个个大小相等的分区(比如:每个分区4KB),每个分区就是一个页框,也叫页帧,即物理页面,是linux划分内存空间的结果。 每个页框都有一个页框号,即内存块号、物理块号。 页 将用户…

深度学习之指数移动平均模型(EMA)介绍

指数移动平均模型(Exponential Moving Average Model,EMA)是一种用于平滑时间序列数据的技术。它通过对数据进行加权平均来减少噪音和波动,从而提取出数据的趋势。 在深度学习中,EMA 常常用于模型的参数更新和优化过程…

完整指南:远程管理 Linux 服务器的 Xshell6 和 Xftp6 使用方法(Xshell无法启动:要继续使用此程序........,的解决方法)

😀前言 在当今软件开发领域,远程管理 Linux 服务器已成为日常工作的重要组成部分。随着团队成员分布在不同的地理位置,远程登录工具的使用变得至关重要,它们为开发人员提供了访问和管理服务器的便捷方式。本文将介绍两款功能强大的…

python随机显示四级词汇 修改版直接显示释义

python随机显示四级词汇 修改版直接显示释义 添加暂停 和继续(按下中建滚轮触发) 按下右键 退出程序 解决在暂停后 ,重新调用update_word 会明显发现每隔5秒更新一次单词的速率已经改变 速率改变的问题可能是由于暂停期间没有清除之前的定时器所导致的。为了确保重新调用updat…

Linux高级进阶-ssh配置

Ubuntu-system 允许使用root远程登陆 apt install ssh -y在/etc/ssh/sshd_config 文件修改PermitRootLogin yes systemctl restart ssh远程连接软件用户名为root

Ubuntu系统中Apache Web服务器的配置与实战

✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…

Educational Codeforces Round 166(Div.2) A~D

A.Verify Password(字符串) 题意: Monocarp正在开发他的新网站,目前面临的挑战是如何让用户选择强密码。 Monocarp认为,强密码应满足以下条件: 密码只能由小写拉丁字母和数字组成;字母后面不…

PasteCode系列系统说明

定义 PasteCode系列是指项目是基于PasteTemplate构建的五层以上项目,包括不仅限于 Domain EntityFrameworkCore Application.Contracts Application HttpApi.Host 熟悉ABP vNext就很好理解了,因为PasteTemplate就是基于ABP的框架精简而来!在…

一些Mysql面试题

InnoDB是如何存储数据的? InnoDB 的数据是按「数据页」为单位来读写的,默认数据页大小为 16 KB。每个数据页之间通过双向链表的形式组织起来,物理上不连续,但是逻辑上连续。 数据页内包含用户记录,每个记录之间用单向…

【java 如何将字符串反转?】

文章目录 概要示例(1)使用StringBuilder的reverse方法(2)使用charAt和循环(3)使用双指针(4)使用递归 总结 概要 在Java中,有多种方法可以将字符串反转,我这里…

代码随想录训练营第二天 977有序数组的平方 209长度最小的子数组 59螺旋矩阵II

第一题: 题目链接:977. 有序数组的平方 - 力扣(LeetCode) 思路: 先将数组求完平方和后进行排序,很简单,主要是排序算法的考察。 这里采用快排 快排的思路: 取这个数组的中间值…

代码随想录算法训练营第四十六 | ● 139.单词拆分 ● 关于多重背包,你该了解这些! ● 背包问题总结篇!

139.单词拆分 视频讲解&#xff1a;https://www.bilibili.com/video/BV1pd4y147Rh https://programmercarl.com/0139.%E5%8D%95%E8%AF%8D%E6%8B%86%E5%88%86.html class Solution { public:bool wordBreak(string s, vector<string>& wordDict) {unordered_set<st…

java stream流之groupby的用法

简单分组 按照年龄对 Person 对象进行分组&#xff1a; 代码示例 import java.util.*; import java.util.stream.Collectors;public class SimpleGrouping {public static void main(String[] args) {List<Person> people Arrays.asList(new Person("Alice"…

上市即交付,比亚迪秦L DM-i万人交车暨千媒众测开营

6月6日&#xff0c;“引领中级 开创油耗2时代”秦L DM-i万人交车暨千媒众测开营仪式在比亚迪大本营深圳盛大举行。 众多车主代表亲临现场&#xff0c;与全国各地的比亚迪4S店千店联动&#xff0c;将秦L DM-i全国交付推向新的高潮。发布即量产&#xff0c;上市即交付&#xff0…