🎗️Golang map
type
status
date
slug
summary
tags
category
icon
password
Blocked by
Blocking
AI summary
go的map
底层数据结构
- go使用拉链法实现了hashMap
- slot中有多个bucket
- 每个bucket中存放,hash后 得mod相同的k&v
- 每一个bucket中存放hash key的高8bit
- 桶超出8个数据后,机会将数据存储在溢出桶中

扩容过程
为什么需要扩容
- map的溢出桶太多会严重影响查询和插入的性能
什么时候需要扩容
- 装载系数超过6.5(平均每个槽6.5个key)
- 使用太多的 溢出桶(溢出桶数量大于普通桶)
扩容策略
- 等量扩容:数据不多,但溢出桶中数据过多(整理)
- 翻倍扩容:数据太多,装载系数大,进行容量翻倍
渐进式驱逐
- 创建新的newBuckets
- oldBuckets指向之前的buckets
- 采用渐进式驱逐,每次操作一个旧桶时,将旧桶驱逐到新桶
- 读取时不进行驱逐,只判断读取新桶还是旧桶
- 旧桶数据驱逐完成后,回收oldBuckets
为什么map不支持并发读写
Go 中
map
的扩容是一个渐进的过程,在我们访问 map
的时候,会对 map
底层实际存储数据的桶进行迁移。如果支持并发读写,就有可能会导致底层定位到的桶是扩容前的,但是实际上数据已经迁移到了新的桶中,这样就会导致访问到的并不是我们想要的数据
sync.Map
- 读多写少的场景
分片锁
- 适合写多读少读场景
如果我们有了解过
MongoDB
,就会知道,MongoDB
中也有分片的概念,当数据量过大时,
单个 MongoDB
实例可能无法存储所有的数据,或者单个实例无法处理过多的读写请求,
这时候就需要将数据分片存储到多个 MongoDB
实例中,也就是按照一定的规则将数据存储到不同的机器上,
然后读写数据的请求也会依据一定规则被路由到对应的机器上。我们需要做的是:通过
key
来计算其 hash
值,然后根据 hash
值来决定将 key
存储到哪个 map
中,
同时,我们每一个 map
都需要加上互斥锁,这样就可以保证每一个 map
的并发安全了。将并发压力分散到多个子map中,将少锁在单个map上的竞争
Prev
MongoDB 总结
Next
epoll
Loading...