添加新元素到空白字典

当第一次往空字典里添加键值对时,程序会根据dict.h/DICT_HT_INITIAL_SIZE 里指定的大

小为d->ht[0]->table 分配空间(在目前的版本中,DICT_HT_INITIAL_SIZE 的值为4 )。

以下是字典空白时的样子:

以下是往空白字典添加了第一个键值对之后的样子:

添加新键值对时发生碰撞处理

在哈希表实现中,当两个不同的键拥有相同的哈希值时,我们称这两个键发生碰撞(collision),

而哈希表实现必须想办法对碰撞进行处理。

字典哈希表所使用的碰撞解决方法被称之为链地址法:这种方法使用链表将多个哈希值相同的

节点串连在一起,从而解决冲突问题。

假设现在有一个带有三个节点的哈希表,如下图:

对于一个新的键值对key4 和value4 ,如果key4 的哈希值和key1 的哈希值相同,那么它们

将在哈希表的0 号索引上发生碰撞。

通过将key4-value4 和key1-value1 两个键值对用链表连接起来,就可以解决碰撞的问题:

添加新键值对时触发了rehash 操作

对于使用链地址法来解决碰撞问题的哈希表dictht 来说,哈希表的性能依赖于它的大小(size

属性)和它所保存的节点的数量(used 属性)之间的比率:

比率在1:1 时,哈希表的性能最好;

如果节点数量比哈希表的大小要大很多的话,那么哈希表就会退化成多个链表,哈希表

本身的性能优势就不再存在;

举个例子,对于下面这个哈希表,平均每次失败查找只需要访问1 个节点(非空节点访问2

次,空节点访问1 次):

而对于下面这个哈希表,平均每次失败查找需要访问5 个节点:

为了在字典的键值对不断增多的情况下保持良好的性能,字典需要对所使用的哈希表(ht[0])

进行rehash 操作:在不修改任何键值对的情况下,对哈希表进行扩容,尽量将比率维持在1:1

左右。

dictAdd 在每次向字典添加新键值对之前,都会对哈希表ht[0] 进行检查,对于ht[0] 的

size 和used 属性,如果它们之间的比率ratio = used / size 满足以下任何一个条件的话,

rehash 过程就会被激活:

1. 自然rehash :ratio >= 1 ,且变量dict_can_resize 为真。

2. 强制rehash : ratio 大于变量dict_force_resize_ratio (目前版本中,

dict_force_resize_ratio 的值为5 )。

Note: 什么时候dict_can_resize 会为假?

在前面介绍字典的应用时也说到过,一个数据库就是一个字典,数据库里的哈希类型键

也是一个字典,当Redis 使用子进程对数据库执行后台持久化任务时(比如执行BGSAVE

或BGREWRITEAOF 时), 为了最大化地利用系统的copy on write 机制, 程序会暂时将

dict_can_resize 设为假,避免执行自然rehash ,从而减少程序对内存的触碰(touch)。

当持久化任务完成之后,dict_can_resize 会重新被设为真。

另一方面,当字典满足了强制rehash 的条件时,即使dict_can_resize 不为真(有BGSAVE

或BGREWRITEAOF 正在执行),这个字典一样会被rehash 。

Rehash 执行过程

字典的rehash 操作实际上就是执行以下任务:

1. 创建一个比ht[0]->table 更大的ht[1]->table ;

2. 将ht[0]->table 中的所有键值对迁移到ht[1]->table ;

3. 将原有ht[0] 的数据清空,并将ht[1] 替换为新的ht[0] ;

经过以上步骤之后,程序就在不改变原有键值对数据的基础上,增大了哈希表的大小。

作为例子,以下四个小节展示了一次对哈希表进行rehash 的完整过程。

1. 开始rehash

这个阶段有两个事情要做:

1. 设置字典的rehashidx 为0 ,标识着rehash 的开始;

2. 为ht[1]->table 分配空间,大小至少为ht[0]->used 的两倍;

这时的字典是这个样子:

Rehash 进行中

在这个阶段,ht[0]->table 的节点会被逐渐迁移到ht[1]->table ,因为rehash 是分多次进

行的(细节在下一节解释),字典的rehashidx 变量会记录rehash 进行到ht[0] 的哪个索引

位置上。

以下是rehashidx 值为2 时,字典的样子:

注意除了节点的移动外,字典的rehashidx 、ht[0]->used 和ht[1]->used 三个属性也产生

了变化。

3. 节点迁移完毕

到了这个阶段,所有的节点都已经从ht[0] 迁移到ht[1] 了:

4. Rehash 完毕

在rehash 的最后阶段,程序会执行以下工作:

1. 释放ht[0] 的空间;

2. 用ht[1] 来代替ht[0] ,使原来的ht[1] 成为新的ht[0] ;

3. 创建一个新的空哈希表,并将它设置为ht[1] ;

4. 将字典的rehashidx 属性设置为-1 ,标识rehash 已停止;

以下是字典rehash 完毕之后的样子:

对比字典rehash 之前和rehash 之后,新的ht[0] 空间更大,并且字典原有的键值对也没有被

修改或者删除。

转载于:https://blog.51cto.com/janephp/1353526

Redisbook学习笔记(1)字典(2)相关推荐

  1. Python学习笔记:字典(dict)

    Python学习笔记:字典(dict) 字典(dict)可能是最重要的Python内置数据结构,更常用的名称是哈希映射(hash map)或关联数组(associate array).它是键值对的集合 ...

  2. 【安全牛学习笔记】字典、在线密码破解-hydra

    字典 按个人信息生成其专属的密码字典 CUPP: Common User Password Profiler - git clone https://github.com/Mebus/cupp.git ...

  3. Object C学习笔记13-Dictionary字典

    通过Array数组和Set集合的学习和理解,可以想象得到Dictionary也分为两种情况了,那就是可变和不可变两种类型的.的确如此,在Object C中提供了两个字典类,分别为NSDictionar ...

  4. Python学习笔记之字典(三)

    嵌套:有时候,需要将一系列字典存储在列表中,或将列表作为值存储在字典中,这称为嵌套.你可以在列表中嵌套字典.在字典中嵌套列表甚至在字典中嵌套字典. 1.字典列表,一个列表里面包含多个字典,即列表中嵌套 ...

  5. Python学习笔记之字典(二)

    遍历字典:一个Python字典可能包含很多个键值对,在需要获取其数据时,就需要对这个进行遍历,Python支持对字典遍历.字典可用于以各种方式存储信息,其中有多种遍历字典的方式:可遍历字典的所有键值对 ...

  6. Python学习笔记之字典(一)

    1.什么是字典:在Python中,字典是一系列键-值对.每个键都与一个值相关联,你可以使用键来访问与之相关联的值.与键相关联的值可以是数字.字符串.列表乃至字典.事实上,可将任何Python对象用作字 ...

  7. 初学Python的学习笔记2----dist字典,set集合,声明函数,函数参数

    2019独角兽企业重金招聘Python工程师标准>>> 7. dist(字典--键值对)d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}---& ...

  8. Redisbook学习笔记(1)跳跃表

    一个典型的跳跃表例子 从图中可以看到,跳跃表主要由以下部分构成: 表头(head):负责维护跳跃表的节点指针.  跳跃表节点:保存着元素值,以及多个层.  层:保存着指向其他元素的指针.高层的指针越过 ...

  9. Redisbook学习笔记(3)数据类型之对象处理机制

    在Redis 的命令中,用于对键(key)进行处理的命令占了很大一部分,而对于键所保存的值的 类型(后简称"键的类型" ),键能执行的命令又各不相同. 比如说,LPUSH 和LLE ...

最新文章

  1. 两条线段相切弧_两条直线间的圆弧连接
  2. linux如何连接移动硬盘
  3. Unity之流光效果
  4. 控制用户的访问之权限、角色【weber出品必属精品】
  5. 【服务端渲染】NuxtJs 综合案例
  6. 2020年二级计算机考试真题,2020年3月计算机等级考试《二级MS Office高级应用》历年真题-试题答案...
  7. 人生永无止境的意思是什么_人生追求永无止境名言
  8. BZOJ 2226 [Spoj 5971] LCMSum 最大公约数之和 | 数论
  9. 【Java TCP/IP Socket】应用程序协议中消息的成帧与解析(含代码)
  10. Python基本知识
  11. 一款基于jQuery可放大预览的图片滑块插件
  12. MOS驱动电路设计需要注意的地方
  13. java健身房管理系统业务_基于SSM的健身房管理系统
  14. 泥瓦匠之 Java 的成长感悟
  15. 安装部署(七) HBase集群安装部署与测试
  16. Linux系统cut命令详解
  17. Docker配置DaoCloud加速器镜像
  18. 微信api调用限制,45009 reach max api daily quota limit 解决方法
  19. Apache Doris 0.11.x 版本升级
  20. 欧洲央行目前已完成数字欧元公众咨询

热门文章

  1. 浙江独立学院计算机专业排名2015,2014-2015年中国独立学院排名
  2. access转sql iif_ACCESS 中的IIF使用
  3. python 获取网页元素_记一次python提取网页标签元素的坑
  4. python程序怎样在手机上_python手机文件怎么上传至电脑?
  5. 特征级融合_多知识图谱的融合算法探索
  6. python画图颜色代码_Python-使用matplotlib创建自己的颜色图并绘制颜色比例
  7. java bundle类_java ResourceBundle介绍
  8. eventlistener java_EventListener原理
  9. python 3.7.4 shell_centos7上Virtualenv从python3.4升级到Python3.7.4
  10. win10 安装db2 10.1 并使用DBserver连接db2数据库