4 回答
TA贡献1155条经验 获得超0个赞
如果并发进程向全局变量写入相同的值会怎样?
数据竞争的结果是不确定的。
运行 Go 数据竞争检测器。
参考:
在 Go 1.6 中,运行时添加了轻量级的、最大努力的映射并发滥用检测。此版本改进了该检测器,支持检测同时写入和遍历映射的程序。
与往常一样,如果一个 goroutine 正在写入 map,则没有其他 goroutine 应该同时读取(包括迭代)或写入 map。如果运行时检测到这种情况,它会打印诊断并使程序崩溃。找出更多有关问题的最佳方法是在竞争检测器下运行程序,这将更可靠地识别竞争并提供更多详细信息。
例如,
package main
import "time"
var linksToVisit = map[string]bool{}
func main() {
someLink := "someLink"
go func() {
for {
linksToVisit[someLink] = true
}
}()
go func() {
for {
linksToVisit[someLink] = true
}
}()
time.Sleep(100 * time.Millisecond)
}
输出:
$ go run racer.go
fatal error: concurrent map writes
$
$ go run -race racer.go
==================
WARNING: DATA RACE
Write at 0x00c000078060 by goroutine 6:
runtime.mapassign_faststr()
/home/peter/go/src/runtime/map_faststr.go:190 +0x0
main.main.func2()
/home/peter/gopath/src/racer.go:16 +0x6a
Previous write at 0x00c000078060 by goroutine 5:
runtime.mapassign_faststr()
/home/peter/go/src/runtime/map_faststr.go:190 +0x0
main.main.func1()
/home/peter/gopath/src/racer.go:11 +0x6a
Goroutine 6 (running) created at:
main.main()
/home/peter/gopath/src/racer.go:14 +0x88
Goroutine 5 (running) created at:
main.main()
/home/peter/gopath/src/racer.go:9 +0x5b
==================
fatal error: concurrent map writes
$
TA贡献1893条经验 获得超10个赞
如果您使用多个 go 例程同时更改相同的值,则最好使用锁。由于当另一个函数正在更改相同值时,无论何时都使用互斥锁和锁来保护值不被访问,就像在访问同一个表时写入数据库表一样。
对于您关于使用具有不同键的地图的问题,在 Go 中并不可取,因为:
map 的典型使用不需要从多个 goroutine 进行安全访问,在需要的情况下,map 可能是某个更大的数据结构或已经同步的计算的一部分。因此,要求所有映射操作都获取一个互斥量会减慢大多数程序的速度并增加少数程序的安全性。
只有在发生更新时,地图访问才是不安全的。只要所有 goroutines 都只是读取——查找地图中的元素,包括使用 for range 循环遍历它——而不是通过分配给元素或进行删除来更改地图,它们就可以安全地同时访问地图而无需同步。
因此,不建议更新地图。有关详细信息,请查看关于为什么映射操作未定义为原子的常见问题解答。
还注意到,如果你真的想去 for 应该有一种方法来同步它们。
映射对于并发使用是不安全的:它没有定义当你同时读取和写入它们时会发生什么。如果您需要从并发执行的 goroutine 读取和写入映射,则访问必须通过某种同步机制进行调解。保护地图的一种常见方法是使用 sync.RWMutex。
- 4 回答
- 0 关注
- 121 浏览
添加回答
举报