16.sync_map
# 01.sync.Map介绍
# 1、sync.Map介绍
sync.Map
是 Go 语言在sync
包中提供的一个并发安全的 map 实现- 旨在解决高并发环境下使用普通 map 时需要手动加锁带来的性能瓶颈问题
sync.Map
通过精心设计的读写机制,保证了在多线程环境下对 map 进行高效的读写操作
# 2、sync.Map特点
read
结构是无锁的,因此读取性能非常高
dirty
操作涉及加锁,但加锁操作被限制在写入和未命中的情况下
,避免了频繁的锁争用
read:
- 一个不变的只读数据结构,它存储了最近的键值对,并且支持并发安全的无锁读操作
sync.Map
尽可能地从read
中读取数据,因为read
是无锁的,因此读操作非常高效
dirty:
- 一个允许修改的 map,用来存储更新后的数据
- 只有当某个键不存在于
read
中时,才会从dirty
中查询数据 - 读写
dirty
是需要加锁的 - 当
dirty
和read
之间不一致时,数据将首先写入dirty
,随后会尝试将部分数据推广到read
中
misses:
- 一个计数器,用来统计从
read
中未命中(即read
中没有找到键值对)且从dirty
中成功读取的次数 - 当
misses
达到一定数量时,会将dirty
中的数据复制到read
,以提升读取命中率并减少锁争用
- 一个计数器,用来统计从
// Map结构体
type Map struct {
mu Mutex // 当涉及到脏数据(dirty)操作时候,需要使用这个锁
read atomic.Value // 不变的只读数据结构
dirty map[interface{}]*entry // 主要用来写,部分时候也承担读的能力
misses int // 记录自从上次更新了read之后,从read读取key失败的次数
}
// readOnly结构体
type readOnly struct {
// m包含所有只读数据,不会进行任何的数据增加和删除操作
// 但是可以修改entry的指针因为这个不会导致map的元素移动
m map[interface{}]*entry
amended bool // 标志位,如果为true则表明当前read只读map的数据不完整
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 3、 dirty
同步 read
情况
1)
misses
达到阈值时
- 当读取操作在
read
中未找到指定的键(未命中),并且从dirty
中成功读取时,sync.Map
会增加misses
计数
2)写入新
key-value
时
- 当要往
sync.Map
中写入一个新的key-value
对时,系统会检查read
和dirty
之间的差异 - 如果
read
中的数据较旧,且dirty
已经有更新,系统会先将dirty
中的数据同步到read
- 目的:通过在写入之前同步
read
和dirty
,系统确保read
尽量保持最新数据,从而减少未来读操作对dirty
的访问
3)
dirty
为nil
时
- 如果
dirty
为nil
,意味着此时所有的数据都在read
中,且没有写入过任何更新 - 目的:确保写操作发生在
dirty
中,同时保持read
不变以供无锁读取
# 02.sync.Map操作
# 1、 写入操作
1、
key原先就存在于read中
,获取key所对应内存地址,原子性修改2、
key原先就存在于read中
,但是key所对应的值被标记为删除状态
- 解除标记,并更新dirty中的key,将
dirty
中的数据批量同步到read
,然后修改key对应的值
- 解除标记,并更新dirty中的key,将
3、
read中没有key,但是dirty中存在这个key
,直接修改dirty中key的值4、
read和dirty中都没有值
,先同步read和dirty的值,然后添加新的key value到dirty上面
# 2、删除数据
- 1、read中没有,且Map存在修改,则尝试删除dirty中的map中的key
- 2、read中没有,且Map不存在修改,那就是没有这个key,无需操作
- 3、read中有,尝试将key对应的值设置为nil,后面读取的时候就知道被删了,
因为dirty中map的值跟read的map中的值指向的都是同一个地址空间,所以,修改了read也就是修改了dirty
# 3、读取
如果在
read
中找到了键值对,则直接返回结果,整个过程是无锁的如果未命中,则尝试从
dirty
中读取,此时需要加锁为了优化性能,在dirty
中找到了数据后,会增加misses
计数如果
misses
达到阈值,则会将dirty
中的内容同步到read
中
上次更新: 2024/10/15 16:27:13