任何人都可以详细说明这一点吗?跨例程的并发读取操作似乎是允许的,但如果尝试读取和写入同一个键,并发读/写操作可能会产生竞争条件。
在某些情况下,这最后的风险可以降低吗?例如:
这不是代码(显然),但我认为它显示了一种情况的轮廓,即使 A 和 B 都尝试访问 m 也不会有竞争条件,或者如果存在竞争条件也没关系,因为额外的约束。
Golang 1.6之前并发读可以,并发写不行,写并发读可以。从 Golang 1.6 开始,map 在写入时无法读取。所以在 Golang 1.6 之后,并发访问映射应该是这样的:
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 }
或者你会得到以下错误:
添加:
您可以通过使用检测种族 go run -race race.go
go run -race race.go
更改read功能:
read
func read() { // lock.RLock() // defer lock.RUnlock() _ = m["a"] }
另一种选择:
众所周知,map是由桶实现的,sync.RWMutex会锁定所有的桶。concurrent-map用于fnv32对键进行分片,每个存储桶使用一个sync.RWMutex.
map
sync.RWMutex
fnv32