在没有锁的情况下,Golang结构并发读写也运行正常吗? [英] golang struct concurrent read and write without Lock is also running ok?
问题描述
concurrentMap()
函数有WARNING: DATA RACE
,致命错误:concurrent map read and map write
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中的任何变量(其中至少有一个是写入)未定义行为。不要试图在未定义的行为中找到逻辑,只需使用适当的同步。未定义意味着它可能"正确"运行,也可能"不正确"运行(给出不正确的结果),或者它可能崩溃或其他任何事情。这就是未定义的意思。点击此处了解更多信息:Is it safe to read a function pointer concurrently without a lock?
您的concurrentStructWithMuLock()
实际上没有数据竞争,因为您正在使用互斥锁来正确同步对结构的访问。
和concurrentMap()
则是另一个问题。Go 1.6 added轻量级并发误用映射检测到运行库:
运行库添加了对并发滥用映射的轻量级尽力而为检测。与往常一样,如果一只大猩猩正在向地图写入数据,则不应该有其他大猩猩同时读取或写入地图。如果运行库检测到此情况,它将打印诊断并使程序崩溃。了解有关该问题的更多信息的最佳方法是在race detector下运行程序,这将更可靠地标识竞争并提供更多详细信息。
因此,这是运行库故意造成的崩溃,因为它检测到对映射的不同步访问。这是Go运行时的一个"功能",它会使你的应用程序崩溃,因为你的应用程序中不应该留下数据竞争(以防止未定义的行为)。点击此处了解更多信息:How to recover from concurrent map writes?
这篇关于在没有锁的情况下,Golang结构并发读写也运行正常吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!