news 2026/6/10 11:31:15

HashTable

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HashTable

我们之前讲的Redis对象Hash这些是一种数据类型,而今天这个学习笔记hashtable是这些类型的具体底层实现。注意要辨别。

那么第一个问题,什么是HASHTABLE?

HASHTABLE,可以想象成目录,要翻看什么内容,直接通过目录能找到页数,翻过去看。如果没有目录,我们需要一页一页往后翻,效率很低。在计算机世界里,HASHTABLE就扮演着这样一个快速索引的角色,通过HASHTABLE我们可以只用O(1)时间复杂度就能快速找到key对应的value。

接着我们看第二个问题,即HASHTABLE的结构

/* This is our hash table structure. */ typedef struct dictt { dictEntry **table; unsigned long size; unsigned long sizemask; unsigned long used; } dictt;

最外层是一个封装的dictht结构,具体的字段含义如下:

  • table:指向实际hash存储。存储可以看做一个数组,所以是*table的表示,石C语言中*table可以表示一个数组。
  • size:哈希表大小。实际就是dictEntry有多少元素空间。size是桶数,不包含链表上的节点
  • sizemask: 哈希表大小的掩码表示,总是等于size-1。这个属性和哈希值一起决定一个键应该被放到table数组的哪个索引上面,规则Index=hash&sizemask
  • used:表示已有节点数量。通过这个字段可以很方便地查询到目前HASHTABLE元素总量。

由上述的定义我们可以知道,used的数量可能大于size

进入第三个知识点,Hash表渐进式扩容:

渐进式扩容顾名思义就是一点一点慢慢扩容,而不是一股脑直接做完,那具体流程是怎样的呢?其实为了实现渐进式扩容,Redis中没有直接把dictht暴露给上层,而是再封装了一层:

可以看到dict结构里面,包含了两个dictht结构,也就是2个HASHTABLE结构。dictEntry是链表结构,也就是用拉链法解决Hash冲突,用的是头插法。

实际上平常使用的就是一个HASHTABLE,在触发扩容之后,就会两个HASHTABLE同时使用,详细过程是这样的:当向字典添加元素时,发现需要扩容就会进行Rehash。Rehash的流程大概分成三步:
首先,为新Hash表ht[1]分配空间。新表大小为第一个大于等于原表2倍used的2次方幂。举个例子,原表如果used=500,2倍就是1000,那第一个大于1000的2次方幂则为1024。此时字典同时持有ht[0]和ht[1]两个哈希表。字典的偏移索引rehashidx从静默状态-1,设置为0,表示Rehash工作正式开始

我们来观察一下rehashidx在途中状态的变化:

  1. 初始状态

    • 在开始 rehash 之前,rehashindex被设置为 -1,表示没有进行 rehash。

    • 当需要开始 rehash 时,rehashindex被设置为 0,第一个桶(索引为0)开始移。

  2. 迁移过程

    • 每次执行增、删、查、改等操作时,Redis 会顺带迁移rehashindex所指向的桶中的所有键值对到新的哈希表。

    • 迁移完一个桶后,rehashindex会加1,指向下一个桶。

    • 这样,每次操作只迁移一个桶,避免了集中迁移导致的长时间阻塞。

  3. 完成迁移

    • rehashindex递增到超过旧哈希表的大小(size)时,表示所有桶都已经迁移完毕。

    • 此时,rehash 完成,旧哈希表被释放,新哈希表替换旧哈希表,rehashindex被重置为 -1。

  4. 关于空桶的处理

    • 在迁移过程中,如果当前rehashindex指向的桶是空的,那么 Redis 会跳过这个桶,并将rehashindex加1,继续检查下一个桶。

    • 这样可以确保迁移过程不会因为遇到空桶而停滞,直到所有非空桶都被迁移。

随着字典操作的不断执行,最后会在某个时间点ht[0]的所有键值对被rehash至ht[1],此时h[1]会替代h[0],然后rehashidx被设置为-1代表扩容结束

停止时机触发条件rehashidx值ht[0].used
正常完成所有键已迁移< size= 0
提前完成中途used=0< size= 0
空桶限制遇到太多空桶< size> 0
遍历完成达到size边界= size应该=0

总结一下,渐进式扩容的核心就是操作时顺带迁移

讲了扩容是怎么实现的,肯定大家会想着,我们啥时候会进行扩容呢?这就是我们最后一个学习的问题,扩容与缩容时机是什么时候?

Redis提出了一个负载因子的概念,负载因子表示目前RedisHASHTABLE的负载情况,是游刃有余,还是不堪重负了。我们设负载因子为k,那么k=ht[0].used/ht[0].size,也就是使用空间和总空间大小的比例。Redis会根据负载因子的情况来扩容:

  1. 负载因子大于等于1,说明此时空间已经非常紧张。新数据是在链表上叠加的,越来越多的数据其实无法在0(1)时间复杂度找到,还需要遍历一次链表,如果此时服务器没有执行BGSAVE或BGREWRITEAOF这两个命令,就会发生扩容。
  2. 负载因子大于5,这时候说明HASHTABLE真的已经不堪重负了,此时即使是有复制命令在进行,也要进行Rehash扩容。

Redis的扩容策略基于负载因子和写时复制机制的权衡:当负载因子≥1时,哈希表性能开始下降,本应触发扩容,但如果此时正在执行BGSAVE或BGREWRITEAOF(会fork子进程并使用写时复制技术),扩容将导致内存页被大量修改,使内存占用量短时间内近翻倍增长,因此Redis选择暂不扩容以优先保证内存稳定;而当负载因子≥5时,哈希表性能已严重恶化,即便有子进程运行,Redis也会强制扩容,因为此时性能损失已远超内存增长的成本。

扩容是数据太多存不下了,那如果太富裕呢,比如原来可能数据较多,发生了扩容,但后面数据不再需要,被删除了,此时多余的空间就是一种浪费。缩容过程其实和扩容是相似的,也是渐进式缩容,这里不赘述。同样的,Redis还是用负载因子来控制什么时候缩容:当负载因子小于0.1,即负载率小于10%,此时进行缩容,新表大小为第一个大于等于原表used的2次方幂。当然,如果有BGSAVE或BGREWRITEAOF这两个复制命令,缩容也会受影响,不会进行。

声明: 本篇笔记仅为学习时整理的笔记以及疑问解决点,无其他任何商业用途,如有侵权联系即删。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 10:53:46

easymall----管理后端分类展示

目的效果 建表思路:categoryId是必须的 标识产品本身 因为是树形结构需要与父id联动 所以需要 pcategoryId 产品本身需要名字 所以需要 category_name 所以最基础的字段只需要这三个 表格展示: sort字段为额外功能 可以通过前端拖动进行人为的排序 可加可不加 control…

作者头像 李华
网站建设 2026/6/10 10:53:53

ue metahuman自动绑定

目录 创建仅关节绑定&#xff1a; 1. 创建完整绑定 报错&#xff1a;无用户登录&#xff0c;请自动触发登录流程 打开 metahuman charter 创建仅关节绑定&#xff1a; 只创建骨骼结构和身体的绑定&#xff0c;不包含面部控制器、表情动画、头发、Groom 等 MetaHuman 特殊资…

作者头像 李华
网站建设 2026/6/10 10:56:05

可用于近红外光谱数据分析的网上公开数据集

可用于近红外光谱数据分析的网上公开数据集 记个小笔记&#xff1a;记录一下最近阅读的论文中出现的用于近红外光谱分析的网上公开数据集 1.药片数据:http://www.eigenvector.com/data/tablets/index.html 该数据集包括两台 NIR 光谱仪测定的 655 个药片的近红外透射谱&#xf…

作者头像 李华
网站建设 2026/6/10 9:19:36

2026年,不管是前端还是后端,最终都是“站长”

以前我们叫“全栈工程师”&#xff0c;听起来像个干苦力的。现在&#xff0c;请叫我“站长”&#xff08;Webmaster&#xff09;。历史的螺旋 还记得 2000 年吗&#xff1f; 那时候没有“前端”和“后端”的区别。你写 HTML&#xff0c;你写 PHP&#xff0c;你配 Apache&#x…

作者头像 李华
网站建设 2026/5/29 3:48:12

大数据毕设项目推荐-基于python+django的大数据短视频分析推荐系统的设计与实现基于django+大数据平台的短视频推荐系统设计与实现【附源码+文档,调试定制服务】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华