You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

验证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参数:
    go test -race -v
    
    若存在数据竞争,Race检测器会输出详细的竞争栈信息,明确指出竞争发生的代码位置。

2. 手动代码审查

针对并发场景逐一排查共享变量的访问逻辑:

  • 检查所有共享字段的读写操作是否都有同步机制(锁、原子操作等);
  • 重点关注sync.Once闭包内的无锁读取操作,确认是否存在与其他goroutine写操作并发执行的可能;
  • 验证64位字段(如uint64、time.Duration)在32位系统上的访问是否有同步保障(32位系统对64位值的读写非原子操作)。

内容的提问来源于stack exchange,提问作者Abhishek Karigar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 02:56:21