无码a片

阿内部试官:谈谈对Redis哈希表的领略

发布日期:2022-06-18 17:09    点击次数:179

阿内部试官:谈谈对Redis哈希表的领略

Hash表总结

哈希表是一种存储数据的结构,他有好多名字(键值对、字典、鲜艳表、映射、联统共组)。在哈希表中,键和值是逐一双应的关系,一个键key对应一个值value。哈希表这个数据结构不错通过键key,在O(1)本领复杂度的情况下取得对应的值。

由于C谈话我方莫得内置哈希表这一数据结构,因此Redis我方已矣了Hash表。

哈希突破及处理目的

哈希表最关节的问题就在于哈希突破。即,两个项,经过哈希函数筹算,发现其对应的存储情势位置一致。关于这种情况,就需要进行进一步处理了。

科罚哈希突破的目的

世界应该背过我写的数据结构与算法八股文背诵版,还铭记科罚Hash突破的方法嘛。

线性探查法(绽放地址)。

这个方法的中枢是:一朝遇见有突破,该项往后顺延.

来看个例子吧。

1.按hash算法,新键值对应该存在箭头所处位置,可惜该位置有值了:

绽放地址法

2.因此需要存储顺延的位置:

绽放地址法

3.顺延位置也有值了,再往后顺延

绽放地址法

4.顺延位置如故有值,再往后顺延,终于存储上了

绽放地址法

链地址法(拉链法)

Redis弃取的方法即是这种拉链法。来看底下例子。新键值对筹算应该存到二号,二号此时照旧有一个键值对了。因此,凯旋通过链表的情势挂到二号键值对1的底下。

拉链法

关于新的键值对亦然如斯,通过链表的情势挂到二号键值对2的底下。

Rehash

在讲rehash之前,最初需要引入一个界说:负载因子。来看一下负载因子的界说吧:

负载因子 = 散列表内元素个数/散列表的长度

要是负载因子高,就评释哈希突破概率大,这么会严重拖慢查找效果。

要是负载因子低,就评释这哈希表大约占用空间太多了,大部分空间都没元素。

为了使负载因子值在合理鸿沟内,措施需要对哈希表进行彭胀或收缩。由于空间变大或松开,之前的键在老表的存储位置,在新表中就不一定相似了, 小12萝8禁在线喷水观看需要再行筹算。这个再行筹算,并把老表元素悠扬到新表元素的历程就叫做rehash。虽然不管是java中的hashmap,concurrenthashmap,如故今天要讲的Redis哈希表,都波及rehash历程。

Redis中哈希表的数据结构

来看一下Redis的Hash表逻辑想象结构 Redis的哈希表主要由三个结构组成:

dictht。单纯默示一个哈希表

dictEntry。哈希表的一项,不错看作即是一个键值对

dict。Redis给外层调用的哈希表结构,包含两个dictht

typedef struct dictht {      dictEntry **table; //哈希表数组(哈希表项逼近)     unsigned long size; //Hash表大小      unsigned long sizemask; //哈希表掩码     unsigned long used;//Hash表已使用的大小 } dictht; 

稍稍讲授一下各个项。

table:哈希表项的指针数组 size:哈希表大小,这应该无谓多讲授吧 sizemask:掩码。这个值其实想象思惟很棒,假定Redis长度是3,你想拜谒第5个元素,要是按之前的方法,那笃定是拜谒到超出redis哈希表鸿沟的地址空间了。是以redis规矩,你想拜谒元素,先把index与size做与,女人与公拘交酡过程高清视频把逾越redis长度的部分就截断了,就不会发生内存安全问题。 Hash表已使用的大小。不明释。

讲了Hash表,来望望哈希项

typedef struct dictEntry {      void *key;      union {          void *val;          uint64_t u64;          int64_t s64;          double d;      } v;      struct dictEntry *next; } dictEntry; 

咱们廓清,Redis弃取拉链法科罚哈希突破的问题。因此,Redis的哈希表项就有一个next指针,指向下一个元素,通过该指针,就不错拜谒多个具有酌量哈希值的键值对。

终末咱们来望望dict结构。

typedef struct dict {     dictType *type;     void *privdata;     dictht ht[2];     int reshaidx; } dict; 

世界笃定很意思,好好的dict,搞两个哈希表做啥?虽然也有不虞思的小伙伴,但没目的,架不住口试官也很意思啊。

谜底揭晓,两个hash表是为了rehash。

那什么情况下需要rehash呢?

要是redis没在实施后台备份,当负载因子大于等于1就实施。(归正CPU闲着亦然闲着) 要是redis在实施后台备份,当负载因子大于等于5就实施。(CPU在干备份了,咱关于真实挤的表改一改,等CPU闲下来,再把稍稍偏挤的rehash)

咱们来看一下要是出现需要rehash的情况,需要的实施设施:

分拨空间给ht[1]。分拨空间由ht[0]的具体参数决定。 将ht[0]存储的键值对,再行筹算hash值和索引值,并赋值到ht[1]的对应位置中。 当赋值完成后,开释ht[0]所占用空间,并把ht[0]指向ht[1]刻下的地址。 ht[1]指向空表。 渐进式rehash

由于设施二弃取的筹算情势要是在一定本领做,占用资源过高,是以redis建议了渐进式rehash的情势。拿大口语来讲,即是原本是一次,一次性的搬运,刻下造成了分批搬运。

在分批搬运的历程中,未免会收到其他种种各样的苦求。

关于写苦求,即往redis哈希表加多新的键值对时,redis会把数据凯旋存放到ht[1]表中。 关于查苦求,即查询特定键对应的值时,redis最初会在ht[0]中查找,要是查找失败,就会在ht[1]表中查找。 关于更新苦求,redis最初会在ht[0]中查找,要是查找失败,就会在ht[1]表中更新。 关于删除苦求,redis最初会在ht[0]中查找,要是查找失败,就会在ht[1]表中删除。

参考

https://www.cnblogs.com/tekkaman/p/5141936.html

https://blog.csdn.net/yangbodong22011/article/details/78467583

Redis的想象与已矣

 

Redis源码剖释与实战

 



栏目分类



Powered by 无码a片 @2013-2022 RSS地图 HTML地图