sync.Map源码分析

概述

go语言中的map并不是并发安全的,在Go 1.6之前,并发读写map会导致读取到脏数据,在1.6之后则程序直接panic,所以go 1.9之前的解决方案是额外绑定一个锁,封装成一个新的struct或者单独使用锁都可以。直到sync.Map出现提供了一种空间换时间有效减少锁的实现方法。

原理

为了减少并发抢锁导致的阻塞,sync.Map分出了read和dirty两个map,里面存的都是指针。存、删和查都先操作read,并用atomic进行并发保护,速度较快,直到read不能满足需求才去操作dirty,操作dirty的时用Mutex锁进行并发保护,速度较慢。

源码分析

主要结构

主要方法

特别提醒

sync.Map在初始化时会将read中所有未删除的数据复制到dirty,而频繁往map中插入新数据会导致dirty中有大量read中没有的数据,从而导致read的命中率过低,需要频繁调用锁进行操作,并且未命中次数达到len(dirty)后,dirty会被升级为read,再次有新数据插入的时候,又会重复dirty初始化的过程。这一系列流程均会造成较大的开销影响整体性能。

适用场景

综上sync.Map适用于读多更新多,新增少的场景。

注:这里更新多特指当read中存在该键且未被标记删除时更新操作,此场景可直接原子更新无需加锁。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据