概述
map
文章目录
- map
- hash与buckets
- 取模法
- 与运算法
- 解决hash冲突
- map in golang
- map的扩容规则
hash与buckets
说到键值对的存储,我们就会想到哈希表,哈希表通常会有一堆桶来存储键值对,一个键值对来了自然要存到一个桶中。首先将key通过hash()处理一下得到一个hash值,现在要利用这个hash值从m个桶中选择一个,桶的编号区间 [0,m-1] 。
取模法
hash%m
与运算法
hash & (m-1)
想要使用与运算法就要限制桶的个数 m 必须是2 的整数次幂,这样 m 的二进制表示一定只有一位为1,(m-1) 就是除了最高为其他均为 1 ,避免一些桶绝对不会被选中的情况
如果之后有其他键值对也选择了同一个桶,就是发生了哈希冲突,解决方案一般是 开放地址法 和 拉链法
- 开放地址法 就是在发生冲突的桶后找没有被占用的桶来存放键值对,查找时定位到桶后hash不匹配,就继续向下找直到遇到空桶。
- 如图
解决hash冲突
- 发生hash冲突会影响hash表的读写效率,选择散列均匀的 hash() 可以减少hash冲突的发生
- 适时对hash表进行扩容意识保障读写效率的有效手段,通常会把
(count of key : value) / m
作为是否需要扩容的判断依据,这个比值被称作负载因子
当需要扩容时,就要分配更多的桶,将旧桶中的数据迁移时,为了避免一次性迁移大量数据带来的性能损耗,通常会在hash表扩容时先分配足够多的新桶,然后用一个字段记录旧桶的位置,再加一个字段记录旧桶迁移的进度(记录下一个要迁移的旧桶编号),在每次hash表读写操作时,如果检测到当前正处于扩容阶段就完成一部分键值对迁移任务,直到所有的键值对迁移完成,旧桶不再使用,算完成了一次扩容操作,这就是所谓渐进式扩容
map in golang
src/runtime/map.go:hmap
type hmap struct {
count int // 已经存储的键值对数目
flags uint8
B uint8 // 桶的数目是 2^B golang使用了与运算法
noverflow uint16 // 溢出桶数量
hash0 uint32 // hash seed
buckets unsafe.Pointer // 桶在哪儿
oldbuckets unsafe.Pointer // 扩容阶段的旧桶位置记录
nevacuate uintptr // 扩容时,下一个要迁移的旧桶编号
extra *mapextra // optional fields
}
再来看看map用的桶长什么样。也就是 bmap
- 一个桶中可以存放8个键值对,但是为了让内存排列更加紧凑,采用 8个键+8个值 的存放方式,在键值对之上是8个
tophash
每个tophash都是对应hash值的高8位,最后的voerflow
bmap指针指向溢出桶
,溢出桶
的结构与常规桶相同,是为了减少扩容次数而引入的。当一个桶存满了,还有可用的溢出桶是时,就会在同种桶后链接一个溢出桶,实际上,如果哈希表要分配的桶的数目大于2^4
时就认为使用到溢出桶的几率较大,就会预分配2^(B-4)
个溢出桶备用,这些溢出桶和常规桶在内存中是连续的 ,前2^B
用作常规桶,后面的用于溢出桶
type mapextra struct {
overflow *[]*bmap // 目前已经被使用的溢出桶的地址
oldoverflow *[]*bmap // 扩容阶段存储存储旧桶用到的那些溢出桶的地址
nextOverflow *bmap //下一个空闲溢出桶
}
如果将这个桶存满的话,接下来再继续存储新的键值对时,这个hash表是会创建溢出桶还是会发生扩容呢?
map的扩容规则
Go语言的map默认负载因子(count / (2^B))是 6.5 (即平均每个buckets存储的键值对达到6.5个以上),超过这个值就会发生翻倍扩容,分配新桶的数目是旧桶的两倍
hamp
中的buckets
指向新分配的两个桶oldbuckets
指向旧桶,bevacuate
为0表示接下来要迁移编号为0的旧桶- 过程如图所示
还有一种情况也会触发扩容,就是负载因子没有超标,但是溢出桶使用较多。 B
<= 15noveflow
> 2^BB
> 15neverflow
>= 2^15
这种情况针对的是在某些极端情况下,例如经过大量的元素增删后,兼职对刚好集中在一小部分buckets中,这时会发生等量扩容,即buckets不变,重新做一次类似增量扩容的迁移动作,将松散的键值对重新排列一次。
最后
以上就是迷你月亮为你收集整理的go专家编程系列(4)常见数据结构 mapmap的全部内容,希望文章能够帮你解决go专家编程系列(4)常见数据结构 mapmap所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复