Go 中的 map 和并发安全问题
在同一时间段内,让不同 goroutine 中的代码对同一个map
进行读写操作是不安全的。map
值本身可能会因这些操作而产生混乱,相关的程序也可能会因此发生不可预知的问题。
我们可以用如下代码展示 map
的并发安全问题。
package main
func main() {
m := make(map[int]int)
go func() {
for {
_ = m[1]
}
}()
go func() {
for {
m[2] = 2
}
}()
select {}
}
错误信息是: fatal error: concurrent map read and map write。
如果你查看 Go 的源代码: hashmap_fast.go#L118,会看到读操作会检查 hashWriting
标志,如果有这个标志,就会报并发错误。
写操作会设置这个标志: hashmap.go#L542
h.flags |= hashWriting
hashmap.go#L628 设置完之后会取消这个标记。
当然,代码中还有好几处并发读写的检查,比如写操作也会检查是否有并发写,删除键的时候类似写,遍历的时候的并发读写问题等。
有时候,map
的并发问题不是那么容易被发现,你可以利用 -race
参数来检查。
那么我们如何保证 map
的并发安全呢?
点击阅读更多看全文。