concurrentMap()函数Have WARNING: DATA RACE和 致命错误 :concurrent map read and map write
concurrentMap()
WARNING: DATA RACE
concurrent map read and map write
concurrentStruct() 有警告:数据竞赛,但运行正常
concurrentStruct()
package main import ( "sync" ) func main() { // concurrentMap() concurrentStruct() // concurrentStructWithMuLock() } type Metadata struct { mu sync.RWMutex // 🔐 key bool } // concurrentStruct 并发操作结构体 // concurrent read and write the struct // go run -race main.go 有 WARNING: DATA RACE,但是可以运行 // go run -race main.go It have WARNING: DATA RACE, But running ok func concurrentStruct() { m := new(Metadata) for i := 0; i < 100000; i++ { go func(metadata *Metadata) { for { readValue := metadata.key if readValue { metadata.key = false } } }(m) go func(metadata *Metadata) { for { metadata.key = true } }(m) } select {} } // concurrentStructWithMuLock 并发操作(使用了读写锁)结构体 // concurrent read and write the struct with RWMutex // go run -race main.go 没有 WARNING: DATA RACE // go run -race main.go Don't have WARNING: DATA RACE, and running ok func concurrentStructWithMuLock() { m := new(Metadata) go func(metadata *Metadata) { for { metadata.mu.Lock() readValue := metadata.key if readValue { metadata.key = false } metadata.mu.Unlock() } }(m) go func(metadata *Metadata) { for { metadata.mu.Lock() metadata.key = true metadata.mu.Unlock() } }(m) select {} } // concurrentMap 并发读写 Map // concurrent read and write the map // go run -race main.go 有 WARNING: DATA RACE,不可运行,fatal error: concurrent map read and map write // go run -race main.go Have WARNING: DATA RACE, And fatal error: concurrent map read and map write func concurrentMap() { m := make(map[int]int) go func() { for { _ = m[1] } }() go func() { for { m[2] = 2 } }() select {} }
从多个goroutine中至少其中一个是写操作的对任何变量的未同步并发访问是 未定义的行为 。不要尝试以未定义的行为查找逻辑,只需使用适当的同步即可。未定义意味着它可能会“正确”运行,也可能“不正确”运行(给出错误的结果),或者崩溃或发生其他任何情况。那就是未定义的意思。
你concurrentStructWithMuLock()居然没有数据的比赛,因为你使用的是互斥正确同步访问结构。
concurrentStructWithMuLock()
而concurrentMap()这是另一个问题。Go1.6向运行时添加了轻量级的并发滥用地图检测功能:
运行时增加了轻巧,尽力而为的检测并发滥用地图的功能。与往常一样,如果一个goroutine正在写入地图,则其他goroutine不应同时读取或写入地图。 如果运行时检测到这种情况,它将打印诊断并使程序崩溃。 找出更多有关该问题的最佳方法是在“ 种族检测器”下运行该程序,这将更可靠地识别种族并提供更多详细信息。
因此,这是运行时的有意崩溃,因为它检测到对映射的非同步访问。这是Go运行时的“功能”,它会使您的应用程序崩溃,因为您的应用程序中不应保留任何数据竞争(以防止发生未定义的行为)。