问题
How do you recover from a runtime panic on a "concurrent map read and map write"? The usual defer with recover doesn't seem to work. Why is that?
I know that you are not supposed to use maps in concurrent contexts, but still: how to recover here?
Example:
package main
import "time"
var m = make(map[string]string)
func main() {
go func() {
for {
m["x"] = "foo"
}
}()
go func() {
for {
m["x"] = "foo"
}
}()
time.Sleep(1 * time.Second)
}
Please add recovery code. :)
回答1:
Recovering doesn't work here because what you experience is not a panicing state.
Go 1.6 added a lightweight concurrent misuse of maps detection to the runtime:
The runtime has added lightweight, best-effort detection of concurrent misuse of maps. As always, if one goroutine is writing to a map, no other goroutine should be reading 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.
What you experience is an intentional crash by the runtime, it's not the result of a panic()
call that a recover()
call in a deferred function could stop.
There's nothing you can do to stop that except prevent the concurrent misuse of maps. If you would leave your app like that and it wouldn't crash, you could experience mysterious, undefined behavior at runtime.
回答2:
Do not recover, guard your code with mutexes form package sync.
package main
import (
"sync"
"time"
)
var m = make(map[string]string)
var l = sync.Mutex{}
func main() {
go func() {
for {
l.Lock()
m["x"] = "foo"
l.Unlock()
}
}()
go func() {
for {
l.Lock()
m["x"] = "foo"
l.Unlock()
}
}()
time.Sleep(1 * time.Second)
}
来源:https://stackoverflow.com/questions/39288741/how-to-recover-from-concurrent-map-writes