没腿的鸟 发表于 2024-1-17 20:11:42

go数据类型-sync.map

定义

在runtime的sync.map包中有定义:
type Map struct {
        mu Mutex // 锁
        read atomic.Pointer //包含了readOnly类型的一个struct,下方把 Pointer 也贴了
        dirty map*entry       // 一个map 存储数据
        misses int          // 错过、没有命中
}

// readOnly is an immutable struct stored atomically in the Map.read field.
type readOnly struct {
        m       map*entry // 一个map,这个map是 read持有的
        amended bool // true if the dirty map contains some key not in m.
    // 追加,这里已经注释了 当dirty 的map中的key 不在 m的map中(就是 read的)就显示为 true
}

// go 的泛型
type Pointer struct {
        _ *T
        _ noCopy
        v unsafe.Pointer
}https://img2023.cnblogs.com/blog/595074/202311/595074-20231129152331151-1995679126.png整体的结构就如上图。
sync.map中有两个map 都是通过指针的形式 ,指向同一份value,但是key两个map都有各自存储。
分析原理

看究竟是如何解决map并发的问题的。
正常读写

https://img2023.cnblogs.com/blog/595074/202311/595074-20231129152755173-1729574065.png正常读写走 m,就是read那个通过泛型结构体指向的那个 map,通过m这个map进行查找后,读取或者更改。
这个时候 misses = 0 ,amended=false追加

https://img2023.cnblogs.com/blog/595074/202311/595074-20231129153549796-1276262532.png如何写一个key,发现m中没有,那么需要去dirty中追加。
开始追加前,需要对dirty进行上锁,写完解锁。
如图现在追加了一个 d,这个时候 m中没有这个d的信息。
这个时候 misses = 0 ,amended=true 这个时候有了 dirty的key 不在m中了。追加后读写

https://img2023.cnblogs.com/blog/595074/202311/595074-20231129153901949-566568945.png这时候就会出现 找d时候,发现m中没有并 amended=true ,就会去 dirty中找,而且每找一次,都会给 misses 加1
这个时候 misses = 1 ,amended=true dirty 提升

当 misses 等于 len(dirty) 就会触发dirty提升,替代m。
https://img2023.cnblogs.com/blog/595074/202311/595074-20231129154455624-1563787695.png当再次出现追加的情况,重塑 dirty
https://img2023.cnblogs.com/blog/595074/202311/595074-20231129155404506-562552969.png这时候把misses = 0 ,amended=false 复原删除

删除比较麻烦,分为正常删除,和在上面的各种状态下进行删除。
正常删除

https://img2023.cnblogs.com/blog/595074/202311/595074-20231129155734969-1504381219.png只需要把pointer置为nil就好,value因为没有对象指向它,在垃圾回收时候,会被标记为白色,被清理。
追加后删除

https://img2023.cnblogs.com/blog/595074/202311/595074-20231129161527497-2033709834.png正常也是置为nil
删除后,提升

https://img2023.cnblogs.com/blog/595074/202311/595074-20231129161224071-2051222430.png提升之后,如果重建 dirty,就不会重建这个d
这里d标记为 expunge 是为了告诉下方,
这个key已经被删除了,不用同步了,如果出现删除d的请求,不需要和下方dirty同步了。
而且当再对D进行追加时候,这时候 m中有d,但是,应该要放到dirty中去完成。总结:

1. map 在扩容时会有并发问题
2.sync.Map 使用了两个map,分离了扩容问题
3.不会引发扩容的操作(查、改)使用read map
4.可能引发扩容的操作(新增)使用 dirty map
5.不是采用读写分离的办法

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: go数据类型-sync.map