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

Go net/http与Gin高并发场景下计数输出重复问题排查

嘿,这个问题我之前做高并发测试的时候也踩过坑!咱们先把核心原因说清楚,再给你解决办法~

问题核心原因

你遇到的重复输出,根本不是打印环节的并发安全问题,而是你获取要打印的count值的方式破坏了原子性:

  • atomic包的单个操作是原子安全的,但如果把「原子累加」和「获取当前值」拆成两个独立的原子操作(比如先Add,再Load),这两个操作之间没有原子性保证。
  • 举个直观的场景:
    1. Goroutine 1 执行atomic.AddInt64(&count, 1),把count从5变成6
    2. Goroutine 2 立刻抢占执行atomic.AddInt64(&count, 1),把count从6变成7
    3. Goroutine 1 再执行atomic.LoadInt64(&count),拿到的是7而不是它自己累加后的6
    4. Goroutine 2 执行atomic.LoadInt64(&count),拿到的也是7
    5. 最终两个goroutine都打印7,就出现了重复

哪怕你把值复制到goroutine里打印,或是用并发安全的log包输出也没用——因为你要打印的值在获取的时候就已经是重复的了。

正确的解决方式

直接用atomic.Add的返回值!这个返回值是原子累加操作的即时结果,和累加操作绑定在一起,完全原子安全:

var count int64

func handler(w http.ResponseWriter, r *http.Request) {
    // Add操作会返回累加后的新值,这个值是当前goroutine原子操作后的准确结果
    newCount := atomic.AddInt64(&count, 1)
    // 不管用fmt还是log打印,这个newCount都是唯一的,不会重复
    log.Println(newCount)
    w.Write([]byte("ok"))
}

这样每个请求对应的goroutine拿到的newCount都是它自己累加后的那个唯一值,绝对不会出现重复输出。

额外注意点

  • 确保你的count变量是int64(或者uint64)类型,atomic包只支持固定宽度的数值类型的原子操作,别用普通的int,否则会有编译错误或者隐性问题。
  • 高并发下如果打印太频繁,控制台输出的顺序可能看起来有点乱(因为goroutine调度的随机性),但每个newCount的值一定是唯一且递增的——这是正常现象,因为打印操作本身是串行的,但累加是并行的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:51:31