第一:运行这个程序不一定每次都能得到panic,这与map并发写的检测机制有关系(见后面)。我在macbook, go 1.16下运行多次该程序,50%得到panic;

第二:使用go run -race可以100%查到第19行的DATA RACE;

第三:示例程序问题在哪里?testB函数创建的ab是一个map类型变量,map类型不支持并发写,你需要用mutex保护它的读写;但代码中创建的多个sync.Mutex互斥的却是map下的一个切片的append,并非map自身。这就是问题所在。

第四:map检测出“concurrent map writes”的原理:$GOROOT/src/runtime/map.go中的mapassign函数中有如下用于检测并发写的代码:

go是通过标志位实现并发写检测。在写之前,先把标志位置为1,写之后,恢复为0。并且每次修改之前都会做判断,如果不符合预期,则会报错。