Go 如果并发进程向全局变量写入相同的值,会发生什么情况?

Go 如果并发进程向全局变量写入相同的值,会发生什么情况?,go,concurrency,goroutine,Go,Concurrency,Goroutine,我只是想知道,如果同时将相同的值写入全局变量,是否有可能导致损坏。我的大脑告诉我这没什么错,因为它只是记忆中的一个位置,但我想我应该再次检查这个假设 我有并发进程写入全局映射var linkstovist map[string]bool。地图实际上是在跟踪网站上需要进一步爬网的链接 然而,在这种情况下,并发进程可能在其各自的页面上具有相同的链接,因此每个进程将同时将相同的链接标记为true。在这种情况下不使用锁没有错,对吗?注意:我从不将值更改回false,因此键存在且其值为true或不存在 即

我只是想知道,如果同时将相同的值写入全局变量,是否有可能导致损坏。我的大脑告诉我这没什么错,因为它只是记忆中的一个位置,但我想我应该再次检查这个假设

我有并发进程写入全局映射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

$