Joh*_* D. 35 concurrency hashmap go
根据Go博客,
映射对于并发使用是不安全的:它没有定义当您同时读取和写入时会发生什么.如果您需要从同时执行的goroutine中读取和写入映射,则访问必须由某种同步机制调解.(来源:https://blog.golang.org/go-maps-in-action)
任何人都可以详细说明这个吗?并发读取操作在例程中似乎是允许的,但是如果尝试读取和写入相同的键,则并发读/写操作可能会生成竞争条件.
在某些情况下可以降低最后的风险吗?例如:
这不是代码(显然),但我认为它显示了一个案例的轮廓,即使A和B都试图访问m,也不会出现竞争条件,或者如果有的话也无关紧要因为额外的限制.
Bry*_*yce 47
在Golang 1.6之前,并发读取可以,并发写入不行,但写入和并发读取都可以.从Golang 1.6开始,映射在写入时无法读取.所以在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
}
Run Code Online (Sandbox Code Playgroud)
添加:
你可以通过使用来检测比赛 go run -race race.go
改变read功能:
func read() {
// lock.RLock()
// defer lock.RUnlock()
_ = m["a"]
}
Run Code Online (Sandbox Code Playgroud)
另一个选择:
众所周知,map由桶实现sync.RWMutex并将锁定所有桶.concurrent-map用于fnv32分割密钥,每个桶使用一个密钥sync.RWMutex.
icz*_*cza 12
并发读取(只读)是可以的.并发写入和/或读取不正常.
如果访问是同步的,则多个goroutine只能写入和/或读取相同的映射,例如通过sync包,通道或通过其他方式.
你的例子:
- 函数A生成k并设置m [k] = 0.这是A写入映射m的唯一时间.已知k不在m中.
- A传递k到函数B并发运行
- A然后读m [k].如果m [k] == 0,则它等待,仅在m [k]!= 0时继续
- B在地图中寻找k.如果找到它,B将m [k]设置为某个正整数.如果不是,则等待直到k为m.
您的示例有2个goroutines:A和B,A尝试读取m(在步骤3中),B尝试同时写入它(在步骤4中).没有同步(你没有提及任何),因此不允许/不确定.
这是什么意思?未确定意味着即使B写m,A可能永远不会观察到变化.或者A可能会观察到甚至没有发生的变化.或者可能发生恐慌.或者地球可能由于这种非同步的并发访问而爆炸(尽管后一种情况的可能性极小,甚至可能小于1e-40).
相关问题:
在Go中使用地图时忽略goroutine /线程安全的危险是什么?
小智 6
您可以使用sync.Map可以安全并发使用的方式。唯一需要注意的是,您将放弃类型安全并更改对映射的所有读取和写入以使用为此类型定义的方法
经过长时间的讨论,我们决定映射的典型使用不需要从多个 goroutine 进行安全访问,并且在需要安全访问的情况下,映射可能是已经同步的某些较大数据结构或计算的一部分。因此,要求所有映射操作获取互斥锁会减慢大多数程序的速度,并增加少数程序的安全性。然而,这不是一个容易的决定,因为这意味着不受控制的地图访问可能会使程序崩溃。
\n\n该语言并不排除原子地图更新。当需要时,例如托管不受信任的程序时,该实现可以互锁映射访问。
\n\n仅当发生更新时地图访问才是不安全的。只要所有 goroutine 仅读取\xe2\x80\x94 查找映射中的元素,包括使用 for range 循环\xe2\x80\x94 进行迭代,并且不通过分配元素或执行删除来更改映射,那么它就是安全的让他们无需同步即可同时访问地图。
\n\n作为正确映射使用的辅助手段,该语言的某些实现包含特殊检查,当并发执行不安全地修改映射时,该检查会在运行时自动报告。
\n