验证Go语言多goroutine调用processSetRequestStatsInfo是否存在数据竞争
Go代码并发调用的数据竞争分析与验证
待分析代码
type setgetRequestInfo struct { mu sync.Mutex once *sync.Once firstSetOccurrence time.Time lastSetOccurrence time.Time countPerClientSet uint64 //if it exceeds max value,it will wrap around to 0 countPerClientGet uint64 cumulativeTime time.Duration setType string } var ( globalSetCount, globalGetCount uint64 = 0, 0 backendSetGetInfomap = &sync.Map{} ) func processSetRequestStatsInfo(key string, setType string, incomingSetReqTime time.Time) { val, loaded := backendSetGetInfomap.LoadOrStore(key, &setgetRequestInfo{setType: setType, once: &sync.Once{}}) if !loaded { info := val.(*setgetRequestInfo) info.once.Do(func() { if info.countPerClientSet == 0 { info.firstSetOccurrence = incomingSetReqTime } }) } if info, ok := val.(*setgetRequestInfo); ok { info.updateStats(incomingSetReqTime) } } func (info *setgetRequestInfo) updateStats(incomingSetReqTime time.Time) { info.mu.Lock() defer info.mu.Unlock() info.countPerClientSet++ info.lastSetOccurrence = incomingSetReqTime info.cumulativeTime += time.Since(incomingSetReqTime) }
数据竞争判断结论
这段代码存在数据竞争,具体竞争点如下:
countPerClientSet的读写竞争:在sync.Once的闭包中,无锁读取info.countPerClientSet;同时其他goroutine可能在updateStats方法中加锁修改该变量。由于读取操作未加锁,会引发读写竞争。firstSetOccurrence的潜在竞争:虽然sync.Once保证闭包只执行一次,但闭包中对firstSetOccurrence的赋值未与updateStats中其他字段的修改同步,在32位系统上还可能因结构体赋值非原子性引发竞争。
验证方法
1. 使用Go内置Race检测器
这是最直接有效的验证方式,步骤如下:
- 编写并发测试用例模拟多goroutine调用:
import ( "sync" "testing" "time" ) func TestProcessSetRequestStatsInfo(t *testing.T) { key := "test-key" setType := "test-type" var wg sync.WaitGroup // 模拟100个goroutine并发调用 for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() processSetRequestStatsInfo(key, setType, time.Now()) }() } wg.Wait() } - 运行测试时添加
-race参数:
若存在数据竞争,Race检测器会输出详细的竞争栈信息,明确指出竞争发生的代码位置。go test -race -v
2. 手动代码审查
针对并发场景逐一排查共享变量的访问逻辑:
- 检查所有共享字段的读写操作是否都有同步机制(锁、原子操作等);
- 重点关注
sync.Once闭包内的无锁读取操作,确认是否存在与其他goroutine写操作并发执行的可能; - 验证64位字段(如
uint64、time.Duration)在32位系统上的访问是否有同步保障(32位系统对64位值的读写非原子操作)。
内容的提问来源于stack exchange,提问作者Abhishek Karigar
相关产品推荐
相关产品推荐

