Golang 映射对于并发读/写操作的安全性如何?
技术问答
242 人阅读
|
0 人回复
|
2023-09-12
|
任何人都能详细解释这一点吗?似乎允许跨例程并发读取操作,但如果尝试读写同一键,并发读/写操作可能会产生竞争条件。
3 Z/ p+ U e( I, U9 U% r; X3 r在某些情况下,最终的风险能降低吗?
0 s$ l# V' }6 x D" r, f函数A生成k并设置m[k]=0。这是 A 写入映射 m唯一一次 。k 不在 m 中。0 m, C! X' N6 F' Z
A 将 k 传递给同时运行的函数 B; R/ K8 m5 k/ n. V9 O
A 然后读 m[k]。如果 m[k]==等待,只当 m[k]!=0 时继续
{/ e p0 S% V" ~4 uB 在地图上寻找 k。如果找到,B 将 m[k] 设置为正整数。如果没有,它会等到 k 在 m 中。即使 A 和 B 都尝试访问 m 没有竞争条件,或者有竞争条件也没关系,因为额外的限制。! _/ b i. W" ]4 P3 M$ |
" f$ i4 B: x/ ^: j
解决方案: # n0 {, {1 J; I9 l- L
Golang 1.6前并发读可以,并发写不可以,写并发读可以。Golang 1.6 开始,map 写入时不能读取。Golang 1.6 之后,并发访问映射应该是这样的:5 U. k8 y7 K$ G. n7 v+ \) t
package mainimport "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}: V3 m, j) O+ V. j
或者你会犯以下错误: * ?0 w2 L" x3 S- ]- X
% \& o+ k) }1 h/ o" U
添加:$ }5 J* q1 W$ |8 D: l7 q& F
通过使用测试种族 go run -race race.go, q) C0 W# _- k; q1 O+ L/ I
更改read功能:; \7 m, e' ?$ l; T& }# c
func read(){ / / lock.RLock() // defer lock.RUnlock() _ = m["a"]}5 C5 s& n2 N8 v% z- t6 S0 `
) X: S3 i( P1 y+ G" J h. u+ F( C' F j
另一种选择:
! _! r# N; W% A/ i( Q J* o: v众所周知,map由桶实现,sync.RWMutex所有的桶都会锁定。concurrent-map用于fnv32对键分片,每个存储桶使用一个sync.RWMutex. |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|
|
|
|
|