回答

收藏

Golang 映射对于并发读/写操作的安全性如何?

技术问答 技术问答 299 人阅读 | 0 人回复 | 2023-09-12

任何人都能详细解释这一点吗?似乎允许跨例程并发读取操作,但如果尝试读写同一键,并发读/写操作可能会产生竞争条件。! u$ r, A3 ]% W8 C& A
在某些情况下,最终的风险能降低吗?
% i. e: {( t! Y* n" Z函数A生成k并设置m[k]=0。这是 A 写入映射 m唯一一次 。k 不在 m 中。
$ O( p4 U! s8 _2 [$ b/ |5 o$ V. TA 将 k 传递给同时运行的函数 B
, H2 P  I  X( y" N# {) \A 然后读 m[k]。如果 m[k]==等待,只当 m[k]!=0 时继续
5 N2 ~2 \* _; W; P( AB 在地图上寻找 k。如果找到,B 将 m[k] 设置为正整数。如果没有,它会等到 k 在 m 中。
即使 A 和 B 都尝试访问 m 没有竞争条件,或者有竞争条件也没关系,因为额外的限制。
9 f; v2 Z) Q& F$ W  M: Y( x                                                                * {  R8 s& M6 U! `- N: U" Y
    解决方案:                                                                ) q3 o! X7 ]) G; d, ~" l. N1 _4 K9 M
                                                                Golang 1.6前并发读可以,并发写不可以,写并发读可以。Golang 1.6 开始,map 写入时不能读取。Golang 1.6 之后,并发访问映射应该是这样的:
, e4 g- e1 W9 r+ R7 a, r
    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}
    7 J8 |) A  L8 x6 v* Y1 S
或者你会犯以下错误: / a2 N- c( g- V1 v! R& T7 g

1 R. O9 ]) m0 [9 ~/ m: U添加:) b8 f' r0 a: C7 f5 P6 L
通过使用测试种族 go run -race race.go( u+ K+ U2 l6 J' O
更改read功能:% f: S+ d6 g$ s' ]1 f% T
    func read(){     / / lock.RLock()    // defer lock.RUnlock()    _ = m["a"]}% j$ }8 L- j( w# E$ l7 r
' N; J- B. t$ {  R

  r. L2 F5 ~/ i$ X8 ^) v另一种选择:
: w) Q* |, f/ w- [- S; A# c众所周知,map由桶实现,sync.RWMutex所有的桶都会锁定。concurrent-map用于fnv32对键分片,每个存储桶使用一个sync.RWMutex.

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则