Go map结构剖析《一》

简介: Go map结构剖析《一》

越是没有本领的就越加自命不凡。——邓拓


1 map结构



Golang的map使用哈希表作为底层实现,一个哈希表里可以有多个哈希表节点,也即bucket,而每个bucket就保存了map中的一个或一组键值对。


map数据结构由runtime/map.go/hmap定义:

type hmap struct {
  // Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.
  // Make sure this stays in sync with the compiler's definition.
  count     int // # live cells == size of map.  Must be first (used by len() builtin)
  flags     uint8
  B         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
  noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
  hash0     uint32 // hash seed
  buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
  oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
  nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)
  extra *mapextra // optional fields
}


1. count  int // 当前保存的元素个数


   2. B  uint8  // 指示bucket数组的大小


   3. buckets  // bucket数组指针,数组的大小为2^B


下图展示一个拥有4个bucket的map:

640.png

本例中, hmap.B=2, 而hmap.buckets长度是2^B为4. 元素经过哈希运算后会落到某个bucket中进行存储。查找过程类似。

bucket很多时候被翻译为桶,所谓的哈希桶实际上就是bucket。


2 bucket数据结构



bucket数据结构由runtime/map.go/bmap定义:


type bmap struct {
    tophash [8]uint8 //存储哈希值的高8位
    data    byte[1]  //key value数据:key/key/key/.../value/value/value...
    overflow *bmap   //溢出bucket的地址
}


每个bucket可以存储8个键值对。

  1. tophash是个长度为8的数组,哈希值相同的键(准确的说是哈希值低位相同的键)存入当前bucket时会将哈希值的高位存储在该数组中,以方便后续匹配。
  2. data区存放的是key-value数据,存放顺序是key/key/key/…value/value/value,如此存放是为了节省字节对齐带来的空间浪费。
  3. overflow 指针指向的是下一个bucket,据此将所有冲突的键连接起来。


注意:上述中data和overflow并不是在结构体中显示定义的,而是直接通过指针运算进行访问的。


下图展示bucket存放8个key-value对:

640.png


3 哈希冲突



当有两个或以上数量的键被哈希到了同一个bucket时,我们称这些键发生了冲突。Go使用链地址法来解决键冲突。由于每个bucket可以存放8个键值对,所以同一个bucket存放超过8个键值对时就会再创建一个键值对,用类似链表的方式将bucket连接起来。

下图展示产生冲突后的map:

640.png

bucket数据结构指示下一个bucket的指针称为overflow bucket,意为当前bucket盛不下而溢出的部分。事实上哈希冲突并不是好事情,它降低了存取效率,好的哈希算法可以保证哈希值的随机性,但冲突过多也是要控制的,后面会再详细介绍。


4 关注公众号



微信公众号:堆栈future



相关文章
|
1月前
|
Go 定位技术 索引
Go 语言Map(集合) | 19
Go 语言Map(集合) | 19
|
2月前
|
存储 算法 Java
Go 通过 Map/Filter/ForEach 等流式 API 高效处理数据
Go 通过 Map/Filter/ForEach 等流式 API 高效处理数据
|
2月前
|
存储 安全 NoSQL
Go map 读写性能优化 - 分片 map
Go map 读写性能优化 - 分片 map
40 1
|
2月前
|
存储 人工智能 安全
go sync.Map 设计与实现
go sync.Map 设计与实现
30 1
|
2月前
|
存储 缓存 Go
如何检查 Go map 是否包含某个键?
【8月更文挑战第31天】
17 0
|
2月前
|
存储 Go 容器
Go从入门到放弃之map(字典)
Go从入门到放弃之map(字典)
|
2月前
|
消息中间件 缓存 API
go-zero微服务实战系列(三、API定义和表结构设计)
go-zero微服务实战系列(三、API定义和表结构设计)
|
2月前
|
存储 Java 关系型数据库
听说过对 Go map 做 GC 吗?
听说过对 Go map 做 GC 吗?
|
2月前
|
算法 安全 Go
|
2月前
|
存储 算法 Go
go map 设计与实现
go map 设计与实现
23 0