Go 如果并发进程向全局变量写入相同的值,会发生什么情况?
我只是想知道,如果同时将相同的值写入全局变量,是否有可能导致损坏。我的大脑告诉我这没什么错,因为它只是记忆中的一个位置,但我想我应该再次检查这个假设 我有并发进程写入全局映射var linkstovist map[string]bool。地图实际上是在跟踪网站上需要进一步爬网的链接 然而,在这种情况下,并发进程可能在其各自的页面上具有相同的链接,因此每个进程将同时将相同的链接标记为true。在这种情况下不使用锁没有错,对吗?注意:我从不将值更改回false,因此键存在且其值为true或不存在 即Go 如果并发进程向全局变量写入相同的值,会发生什么情况?,go,concurrency,goroutine,Go,Concurrency,Goroutine,我只是想知道,如果同时将相同的值写入全局变量,是否有可能导致损坏。我的大脑告诉我这没什么错,因为它只是记忆中的一个位置,但我想我应该再次检查这个假设 我有并发进程写入全局映射var linkstovist map[string]bool。地图实际上是在跟踪网站上需要进一步爬网的链接 然而,在这种情况下,并发进程可能在其各自的页面上具有相同的链接,因此每个进程将同时将相同的链接标记为true。在这种情况下不使用锁没有错,对吗?注意:我从不将值更改回false,因此键存在且其值为true或不存在 即
并发映射写入不正常,因此很可能会出现致命错误。因此我认为应该使用锁如果同时使用多个go例程更改相同的值,则最好使用锁。因为互斥和锁在任何时候都会被使用,以防止在另一个函数更改值时访问该值,就像在访问同一个表时写入数据库表一样 对于您关于使用具有不同键的地图的问题,最好不要在Go中使用,因为: 地图的典型使用不需要来自多个站点的安全访问 goroutines,在那些它确实存在的情况下,地图可能是其中的一部分 一些已经存在的更大的数据结构或计算 同步的。因此要求所有映射操作都获取互斥锁 会降低大多数程序的速度,为少数程序增加安全性 只有在发生更新时,地图访问才不安全。只要所有 goroutine只在地图中查找元素,包括 使用for range循环遍历它,并且不更改映射 通过分配给元素或执行删除操作,它们可以安全地 在不同步的情况下并发访问映射 因此,在地图更新的情况下,不建议这样做。有关为什么未定义原子映射操作的详细信息 还需要注意的是,如果您真的想继续,应该有一种方法来同步它们 地图对于并发使用是不安全的:它没有定义发生了什么 当你同时读和写的时候。如果你需要阅读 从并发执行的goroutines开始并从中写入映射 访问必须通过某种同步机制进行调解。 保护地图的一种常见方法是使用sync.RWMutex 如果并发进程向全局变量写入 同样的价值 数据竞争的结果是未定义的 运行Go数据竞赛检测器 参考资料: 在Go1.6中,运行时添加了轻量级的、尽力而为的检测 同时滥用地图。此版本使用 支持检测并发写入和迭代的程序 在地图上 和往常一样,如果一个goroutine正在向地图写入,那么没有其他goroutine 应该是阅读,包括迭代或编写地图 同时如果运行时检测到这种情况,它将打印一个 诊断并使程序崩溃。了解更多信息的最佳方式 问题是在竞赛检测器下运行程序,这将 更可靠地识别种族并提供更多细节 比如说,
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
$
从Go 1.6开始,同步映射写入将导致死机。使用同步访问 请参见映射值分配实现:
不确定为什么-1。。。我没有收到致命错误,但您是说并发写入映射是不好的,因为并发进程可能会写入不同的键?或者你是说并发映射写入即使在同一个键上也不行?当并发写入发生时,行为是未定义的,我想没有人喜欢这样,对吧?当你同时插入一个键时,它肯定是有问题的。地图的基本结构可能会增长和变化,从而导致混乱。当您使用相同的布尔值写入同一个键时,它可能没有那么糟糕,但由于编译器实现细节的原因,它可能是一种未定义的行为。阅读更多信息:Go还有一个种族检测器@是的,在我问了这个问题之后,我才意识到这种情况。如果你想把它放在一个答案中,我会接受的。你能分享你从哪里得到的文档链接吗?
$ 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
$