golang yaml.v2 空map_搬砖程序员带你阅读 Go map的实现(四)map的扩容和迁移

本文详细探讨了Go语言中map的扩容和迁移过程,包括数据结构、赋值操作、扩容条件、数据搬迁策略等。在赋值时,若发现hash冲突过多或空bucket过多,会触发扩容和数据迁移。扩容可能导致新bucket数组大小翻倍,而数据迁移则是逐步进行的,每次赋值可能涉及一次搬迁。理解这些机制有助于优化Go程序中map的使用。
摘要由CSDN通过智能技术生成

9bb26aa69944001616bd80a0584c953e.png

027eaa49a2f4164b530468e30e6f4f44.png 027eaa49a2f4164b530468e30e6f4f44.png

golang map 操作,是map 实现中较复杂的逻辑。因为当赋值时,为了减少hash 冲突链的长度过长问题,会做map 的扩容以及数据的迁移。而map 的扩容以及数据的迁移也是关注的重点。

027eaa49a2f4164b530468e30e6f4f44.png 027eaa49a2f4164b530468e30e6f4f44.png数据结构

首先,我们需要重新学习下map实现的数据结构:

type hmap struct {
    
  count int
  flags uint8  
  B uint8
  noverflow uint16
  hash0 uint32
  buckets unsafe.Pointer
  oldbuckets unsafe.Pointer
  nevacuate uintptr
  extra *mapextra
}

type mapextra struct {
  overflow *[]*bmap
  oldoverflow *[]*bmap
  nextOverflow *bmap
}

hmap 是 map 实现的结构体。大部分字段在 第一节中已经学习过了。剩余的就是nevacuate 和extra 了。

首先需要了解搬迁的概念:当hash 中数据链太长,或者空的bucket 太多时,会操作数据搬迁,将数据挪到一个新的bucket 上,就的bucket数组成为了oldbuckets。bucket的搬迁不是一次就搬完的,是访问到对应的bucket时才可能会触发搬迁操作。(这一点是不是和redis 的扩容比较类似,将扩容放在多个访问上,减少了单次访问的延迟压力)

  • nevactuate 标识的是搬迁的位置(也可以考虑为搬迁的进度)。标识目前 oldbuckets 中 (一个 array)bucket 搬迁到哪里了。

  • extra 是一个map 的结构体,nextOverflow 标识的是申请的空的bucket,用于之后解决冲突时使用;overflow 和 oldoverflow 标识溢出的链表中正在使用的bucket 数据。old 和非old 的区别是,old 是为搬迁的数据。

理解了大概的数据结构,我们可以学习map的 赋值操作了。

map 赋值操作

map 的赋值操作写法如下:

data := mapExample["hello"]

赋值的实现,golang 为了对不同类型k做了优化,下面是一些实现方法:

func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {}func mapassign_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {}func mapassign_fast32ptr(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {}func mapassign_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {}func mapassign_fast64ptr(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer{}func mapassign_faststr(t *maptype, h *hmap, s string) unsafe.Pointer {}

内容大同小异,我们主要学习mapassign 的实现。 

mapassign 方法的实现是查找一个空的bucket,把key赋值到bucket上,然后把val的地址返回,然后直接通过汇编做内存拷贝。

那我们一步步看是如何找空闲bucket的:

①  在查找key之前,会做异常检测,校验map是否未初始化,或正在并发写操作,如果存在,则抛出异常:(这就是为什么map 并发写回panic的原因)

if h == nil {
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值