Golang并发下的数据结构及其底层剖析

Go中“0字节”
  1. int

sizeof 查看字节数
int 8字节 64位;4字节 32位(根据系统)
int32永远4字节
指针也是跟随系统字长,其底层其实是无符号的64位整型

  1. 空结构体

空结构体有地址没内存
空结构体独立的地址都为 zerobase(指针)
%p 打印地址
主要为了节约内存
map【string】struct{}{},相当于hashset 只有键没有值
chan的负载可以为空结构体,当发信号使用
nil不能是空结构体

数组字符串切片
  1. 字符串

底层为结构体 ,runtime包中unsafe.Pointer 指向byte数组
unicode 统一的字符集,至少3 个字节表示,utf8变长格式
访问字符串"你好"fori得到每个字节,forr range自动解码为rune
rune就是utf8

  1. 切片

字面量创建 []int{} 编译时确定
运行时创建 make() 直接调用runtime的makeSlice

因为数组是连续的空间,继续用原来的数组可能到达其他变量的空间,所以切片扩容新开数组
切片扩容时,并发不安全,注意加锁(第一个协程追加扩容老切片废除,第二个协程读取老切片的值就会出问题)

map

redis的本质就是一个大的hashmap

a:A 举例:
先对key(a)哈希取位置
开放寻址法一直找到不为空的值插入
取的话也是一样,a哈希找位置,不为a则往后找
拉链法横向的对应槽(Slot),每个槽对用的kv为桶

  1. hmap,bmap

map在go中底层为: hmap,其中:
count kv个数
hash0 代表哈希种子,哈希算法用到
buckets 中有 2的B次幂个 桶(bmap)

bmap
tophash 哈希数组(哈希值的高8位) —> 为了快速访问
keys elems kv数组
overflow 指针,如果这个bmap 超过 8 个还要存,那么指向 新的 bmap

  1. 初始化

调用make初始化
先确定B,先创建正常的bmap,同时会多创建几个溢出桶,
hmap 底层有 NextOverflow 指向下一个可用的溢出桶,bmap中的overflow指针溢出后会指向该桶

字面量初始化
掉用make,然后赋值

  1. 访问:

hash0 + key 确认桶号
通过B 取二进制后几位确认桶
然后找tophash ,key 和 溢出桶的hash
没找到说明key 不存在,写入同样操作,没有的话插入一个

map扩容

哈希碰撞严重,map桶溢出太多,趋向链表
太多溢出桶(溢出桶>普通桶)

整理(等量)扩容 – >溢出桶太多(存在之前的数据被删掉导致)
翻倍扩容(数据太多)
创建一组新桶
oldbuckets 指向原有的桶数组,buckets指向新的桶数组
map标记(flags)为扩容状态

渐进式驱逐
每次操作一个旧桶,将旧桶数据驱逐到新桶(根据B操作进行划分)
所有旧桶驱逐完毕,oldbuckets 回收

map并发操作

A协程读取时桶不会驱逐,B协程写入驱逐这个桶
map加锁会影响性能

Map
  1. 总结构:

Mutex
read 下面有个万能map
dirty 下面有个map
misses 没有命中
将不会扩容的操作和扩容的操作分离

正常的话走read ,找到的话修改即可
找不到的话,上锁,操作dirtymap,所以每次只有一个协程操作dirtymap
然后read中的amended 为true,表示有追加,说明read中map数据不准确,修改和读走read就行
只有追加元素可能扩容时才走dirtymap
如果在dirtymap中读到键值,则misses+1
misses = len(dirtmap) ,dirty提升变为read中map
追加false ,misses=0,dirtymap = nil(走dirty时在变为和read中一样)

删除更麻烦
正常删除,追加为false,将k后的指针置为nil,指不到v了,过段时间GC就会将v干掉
追加后的删除,指针为nil
上提后dirtymap重建时,指针为expunded(删除)
访问read时直接将其干掉就行,因为dirty中没有,不用考虑一致的问题

接口

结构体实现接口,底层会实现值和指针的方法
而指针实现接口,底层只实现指针的方法

正常接口 iface,空接口 eface 除了指针,第一个字段比较简单(类型)
其实是用eface承载传入,最大用途任意类型入参

内存对齐

CPU操作数据按照字长来操作
跨字长变量影响原子操作,并且影响性能
基本类型根据对齐系数判断放置位置

结构体偏移量可通过调整成员顺序节省空间,最后分情况补长
根据结构体的对其系数判断第一个位置的地址

空结构体独立使用地址默认,包在其他结构体中则不一定

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值