为什么需要 sync map
go 语言之所以引入 sync.Map
主要是因为GO
语言自带的 map
是线程不安全的。只能保证并发的读,但是不能保证并发的写。
看下面的例子:
func main() {
m := make(map[int]int)
go func() {
for {
m[1] = 1 // 并发的写
}
}()
go func() {
for {
_ = m[1] //并发的读
}
}()
time.Sleep(time.Hour)
}
运行结果如下
注意:
-
出现这种现象的原因,主要是因为:错误信息显示,并发的 map 读和 map 写,也就是说使用了两个并发函数不断地对 map 进行读和写而发生了竞态问题,map 内部会对这种并发操作进行检查并提前发现。
-
其实,就算你在 第一个协程和第二个协程中间,加上
time.Sleep(time.Second)
,依然也会报panic
。
使用 sync.map
代码如下,再并发的读写,就不会报错了。
func main() {
var m sync.Map
go func() {
m.Store(1, "小张")
}()
time.Sleep(time.Second)
go func() {
v, ok := m.Load(1)
if ok {
fmt.Println(v.(string))
}
}()
time.Sleep(time.Second)
}
如果想把 sync.map 中的 key 和 value 遍历出来,需要用 sync.map 自带的特殊方法
func main() {
var m sync.Map
go func() {
m.Store(1, "小张")
}()
time.Sleep(time.Second)
go func() {
v, ok := m.Load(1)
if ok {
fmt.Println(v.(string))
}
}()
time.Sleep(time.Second)
// 遍历 sync.map 中的 key,val
m.Range(func(key, value interface{}) bool {
fmt.Println("key:", key.(int), "value", value.(string))
return true
})
}