Executing below program with go run.
yields fatal errors such as
fatal error: concurrent map writes
goroutine 103 [running]:
...
The runtime detects the racy access on the map
, but not on the slice
Why it is so ?
This is the program i have written:
package main
import (
"time"
)
func main() {
m := map[string]int{"a":1}
s := []int{1}
for i := 0; i < 1000; i {
go func() {
m["a"] = i
s[0] = i
}()
}
time.Sleep(3 * time.Second)
}
CodePudding user response:
The builtin race detector in maps is low-hanging fruit. The feature uses a spare bit in the map header for storage. The feature has a very low CPU cost. Search for hashWriting
in runtime/map.go to see the implementation.
A builtin in race detector for slices will incur memory overhead, CPU overhead or both because each slice element is a separate variable in the memory model. There's not a spare bit per slice element to use in a race detector implementation.
Use the Go Race Detector to detect all data races including races on slice elements. The Go Race Detector instruments the code to record and detect how memory is accessed.
CodePudding user response:
Firstly, assuming we're talking about modifying the contents of the slice (not the slice definition itself), slices are safe for concurrent read/write so long as you don't concurrently modify the same exact element at the same time. This means that to accurately detect incorrect concurrent access, you would need to track it on a per-element basis. This would be an excessive memory overhead.
Secondly, slices are intended as a thin abstraction over arrays, which themselves are a thin abstraction over direct memory access (within a constrained range). That is to say, the operation is expected to be very fast. Detecting incorrect concurrent access at the language level would be an excessive processing overhead.
In the case of maps, both the memory and processing overhead of using the data structure in the first place is enough to dwarf the cost of running this concurrency check. Therefore, it is seen as a net-positive to have this handy safety feature built in.
You can indeed detect data races on slices using Go's race detector, but as noted by the documentation:
The cost of race detection varies by program, but for a typical program, memory usage may increase by 5-10x and execution time by 2-20x.
CodePudding user response:
the runtime is kind enough to warn the end user when a racy access happens even though the race detector was not enabled.
If you execute that program with the race detector enabled like in go run -race .
you get such output
$ go run -race .
...
==================
WARNING: DATA RACE
Write at 0x00c000124000 by goroutine 8:
main.main.func1()
/home/mh-cbon/gow/src/test/d/dr/main.go:14 0xd7
Previous write at 0x00c000124000 by goroutine 6:
main.main.func1()
/home/mh-cbon/gow/src/test/d/dr/main.go:14 0xd7
Goroutine 8 (running) created at:
main.main()
/home/mh-cbon/gow/src/test/d/dr/main.go:12 0x12a
Goroutine 6 (finished) created at:
main.main()
/home/mh-cbon/gow/src/test/d/dr/main.go:12 0x12a
==================
Found 4 data race(s)
exit status 66
Which means that at line 14 (s[0] = i
) there is concurrent access started at line 12 go func() {
.
Read more about the race detector at https://go.dev/blog/race-detector