代码之家  ›  专栏  ›  技术社区  ›  Terence Chow

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

  •  1
  • Terence Chow  · 技术社区  · 6 年前

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

    var linksToVisit map[string]bool . 地图实际上是在跟踪网站上需要进一步爬网的链接。

    但是,并发进程可能在其各自的页面上具有相同的链接,因此每个进程都将该链接标记为 true 同时。在这种情况下不用锁没什么不对吧?注意:我从不将值改回 false

    即。

    var linksToVisit = map[string]bool{}
    
    ... 
    // somewhere later a goroutine finds a link and marks it as true
    // it is never marked as false anywhere
    linksToVisit[someLink] = true 
    
    4 回复  |  直到 6 年前
        1
  •  1
  •   peterSO    6 年前

    如果并发进程向全局变量写入 同样的价值?

    数据竞争的结果未定义。

    运行Go数据竞争检测器。

    参考文献:

    Wikipedia: Race condition

    Benign Data Races: What Could Possibly Go Wrong?

    The Go Blog: Introducing the Go Race Detector

    Go: Data Race Detector


    Go 1.8 Release Notes

    Concurrent Map Misuse

    同时滥用地图。这个版本改进了探测器 支持检测同时写入和迭代的程序 在地图上。

    和往常一样,如果一个goroutine正在写地图,那么没有其他goroutine 应该是读取(包括迭代)或写入映射 同时。如果运行库检测到这种情况,它将打印 问题是在race检测器下运行程序,它将 更可靠地确定种族并给出更多细节。


    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
    
    $
    

        2
  •  0
  •   Raggaer    6 年前

    并发映射写入不正常,因此很可能会出现致命错误。所以我想应该用锁

        3
  •  0
  •   Himanshu    6 年前

    如果同时使用多个go例程更改同一个值,则最好使用锁。因为互斥锁和锁在另一个函数更改相同值时用于保护值不被访问,就像在访问同一个表时写入数据库表一样。

    对于使用不同键的地图的问题,最好不要使用“转到:

    地图的典型使用不需要从多个 在这种情况下,地图可能是一部分 同步。因此,要求所有映射操作都获取一个互斥锁 会减慢大多数程序的速度,增加少数程序的安全性。

    goroutines只准备在地图中查找元素,包括 使用for-range循环遍历它而不更改映射 同时访问映射而不进行同步。

    Check FAQ 关于为什么映射操作没有定义原子。

    另外,如果你真的想去,应该有一种方法来同步它们。

    当你同时读和写的时候。如果你需要阅读 从并发执行goroutines的映射写入 访问必须通过某种同步机制进行中介。 保护地图的一种常见方法是使用sync.RWMutex。