问题描述
根据 Go 博客,
地图对于并发使用是不安全的:它没有定义当您同时读取和写入它们时会发生什么.如果您需要从并发执行的 goroutine 中读取和写入映射,则必须通过某种同步机制来调节访问.(来源:
添加:
您可以使用 go run -race race.go
更改读取
功能:
func read() {//lock.RLock()//延迟 lock.RUnlock()_ = m["a"]}
另一个选择:
众所周知,map
是由桶实现的,sync.RWMutex
会锁定所有桶.concurrent-map 使用 fnv32
对密钥进行分片,每个桶使用一个sync.RWMutex
.
According to the Go blog,
Can anyone elaborate on this? Concurrent read operations seem permissible across routines, but concurrent read/write operations may generate a race condition if one attempts to read from and write to the same key.
Can this last risk be reduced in some cases? For example:
- Function A generates k and sets m[k]=0. This is the only time A writes to map m. k is known to not be in m.
- A passes k to function B running concurrently
- A then reads m[k]. If m[k]==0, it waits, continuing only when m[k]!=0
- B looks for k in the map. If it finds it, B sets m[k] to some positive integer. If it doesn't it waits until k is in m.
This isn't code (obviously) but I think it shows the outlines of a case where even if A and B both try to access m there won't be a race condition, or if there is it won't matter because of the additional constraints.
Before Golang 1.6, concurrent read is OK, concurrent write is not OK, but write and concurrent read is OK. Since Golang 1.6, map cannot be read when it's being written.So After Golang 1.6, concurrent access map should be like:
package main
import (
"sync"
"time"
)
var m = map[string]int{"a": 1}
var lock = sync.RWMutex{}
func main() {
go Read()
time.Sleep(1 * time.Second)
go Write()
time.Sleep(1 * time.Minute)
}
func Read() {
for {
read()
}
}
func Write() {
for {
write()
}
}
func read() {
lock.RLock()
defer lock.RUnlock()
_ = m["a"]
}
func write() {
lock.Lock()
defer lock.Unlock()
m["b"] = 2
}
Or you will get the error below:
ADDED:
You can detect the race by using go run -race race.go
Change the read
function:
func read() {
// lock.RLock()
// defer lock.RUnlock()
_ = m["a"]
}
Another choise:
As we known, map
was implemented by buckets and sync.RWMutex
will lock all the buckets. concurrent-map use fnv32
to shard the key and every bucket use one sync.RWMutex
.
这篇关于并发读/写操作的 Golang 映射有多安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!