如果并发进程向全局变量写入相同的值会怎样?
What happens if concurrent processes write to a global variable the same value?
我只是想知道是否有可能由于同时将相同的值写入全局变量而导致损坏。我的大脑告诉我这没有任何问题,因为它只是内存中的一个位置,但我想我应该仔细检查这个假设。
我有并发进程写入全局映射 var linksToVisit map[string]bool
。该地图实际上是在跟踪网站上 link 需要进一步抓取的内容。
然而,并发进程可能在各自的页面上具有相同的 link,因此每个进程都会同时将相同的 link 标记为 true
。在这种情况下不使用锁没有错吧?注意:我从不将该值改回 false
,因此该键存在且其值为 true 或不存在。
即
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
并发映射写入不正常,因此您很可能会遇到致命错误。所以我觉得应该用锁
如果您使用多个 go 例程同时更改相同的值,则最好使用锁。由于当另一个函数正在更改相同内容时,无论何时使用互斥锁和锁来保护值不被访问,就像在访问相同的 table.
时写入数据库 table
关于使用具有不同键的映射的问题在 Go 中是不可取的:
The typical use of maps did not require safe access from multiple
goroutines, and in those cases where it did, the map was probably part
of some larger data structure or computation that was already
synchronized. Therefore requiring that all map operations grab a mutex
would slow down most programs and add safety to few.
Map access is unsafe only when updates are occurring. As long as all
goroutines are only reading—looking up elements in the map, including
iterating through it using a for range loop—and not changing the map
by assigning to elements or doing deletions, it is safe for them to
access the map concurrently without synchronization.
所以不建议更新地图。有关为什么未定义原子映射操作的更多信息Check FAQ。
还注意到,如果你真的想去 for 应该有一种同步它们的方法。
Maps are not safe for concurrent use: it's not defined what happens
when you read and write to them simultaneously. If you need to read
from and write to a map from concurrently executing goroutines, the
accesses must be mediated by some kind of synchronization mechanism.
One common way to protect maps is with sync.RWMutex.
What happens if concurrent processes write to a global variable the
same value?
数据竞争的结果是不确定的。
运行 Go 数据竞争检测器。
参考文献:
Benign Data Races: What Could Possibly Go Wrong?
The Go Blog: Introducing the Go Race Detector
In Go 1.6, the runtime added lightweight, best-effort detection of
concurrent misuse of maps. This release improves that detector with
support for detecting programs that concurrently write to and iterate
over a map.
As always, if one goroutine is writing to a map, no other goroutine
should be reading (which includes iterating) or writing the map
concurrently. If the runtime detects this condition, it prints a
diagnosis and crashes the program. The best way to find out more about
the problem is to run the program under the race detector, which will
more reliably identify the race and give more detail.
例如,
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 开始,同时映射写入将导致 panic
。使用 sync.Map
同步访问。
我只是想知道是否有可能由于同时将相同的值写入全局变量而导致损坏。我的大脑告诉我这没有任何问题,因为它只是内存中的一个位置,但我想我应该仔细检查这个假设。
我有并发进程写入全局映射 var linksToVisit map[string]bool
。该地图实际上是在跟踪网站上 link 需要进一步抓取的内容。
然而,并发进程可能在各自的页面上具有相同的 link,因此每个进程都会同时将相同的 link 标记为 true
。在这种情况下不使用锁没有错吧?注意:我从不将该值改回 false
,因此该键存在且其值为 true 或不存在。
即
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
并发映射写入不正常,因此您很可能会遇到致命错误。所以我觉得应该用锁
如果您使用多个 go 例程同时更改相同的值,则最好使用锁。由于当另一个函数正在更改相同内容时,无论何时使用互斥锁和锁来保护值不被访问,就像在访问相同的 table.
时写入数据库 table关于使用具有不同键的映射的问题在 Go 中是不可取的:
The typical use of maps did not require safe access from multiple goroutines, and in those cases where it did, the map was probably part of some larger data structure or computation that was already synchronized. Therefore requiring that all map operations grab a mutex would slow down most programs and add safety to few.
Map access is unsafe only when updates are occurring. As long as all goroutines are only reading—looking up elements in the map, including iterating through it using a for range loop—and not changing the map by assigning to elements or doing deletions, it is safe for them to access the map concurrently without synchronization.
所以不建议更新地图。有关为什么未定义原子映射操作的更多信息Check FAQ。
还注意到,如果你真的想去 for 应该有一种同步它们的方法。
Maps are not safe for concurrent use: it's not defined what happens when you read and write to them simultaneously. If you need to read from and write to a map from concurrently executing goroutines, the accesses must be mediated by some kind of synchronization mechanism. One common way to protect maps is with sync.RWMutex.
What happens if concurrent processes write to a global variable the same value?
数据竞争的结果是不确定的。
运行 Go 数据竞争检测器。
参考文献:
Benign Data Races: What Could Possibly Go Wrong?
The Go Blog: Introducing the Go Race Detector
In Go 1.6, the runtime added lightweight, best-effort detection of concurrent misuse of maps. This release improves that detector with support for detecting programs that concurrently write to and iterate over a map.
As always, if one goroutine is writing to a map, no other goroutine should be reading (which includes iterating) or writing the map concurrently. If the runtime detects this condition, it prints a diagnosis and crashes the program. The best way to find out more about the problem is to run the program under the race detector, which will more reliably identify the race and give more detail.
例如,
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 开始,同时映射写入将导致 panic
。使用 sync.Map
同步访问。