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

Golang同值并发写入uint64变量是否必须用互斥锁或原子变量?

问题相关代码

type simpleTx struct {
    gas uint64
}

func (tx *simpleTx) UpdateGas() {
    tx.gas = 125
}

func TestUpdateGas(t *testing.T) {
    var wg sync.WaitGroup
    wg.Add(100)

    tx := &simpleTx{}
    for i:=0; i <100; i++ {
        go func(t *simpleTx) {
            tx.UpdateGas()
            wg.Done()
        }(tx)
    }

    wg.Wait()
}

上述测试用例使用-race选项运行时会输出"WARNING:DATA RACE"数据竞争警告。

问题解答

  1. Go语言中不存在支持相同值并发写入的原生类型
    根据Go内存模型的定义,只要多个goroutine并发访问同一块内存地址、且至少有一个访问是写操作、同时没有同步机制约束,无论写入的值是否完全相同,都属于数据竞争,属于未定义行为,race检测器必然会触发告警。哪怕所有写入操作都是赋值同一个固定值,也不会被Go语言规范特殊对待,不会自动规避数据竞争。

  2. 这类同值并发写入场景必须使用同步机制,但可选方案不止互斥锁和atomic原子变量
    所有同步方案本质上都需要满足Go内存模型的可见性和原子性要求,常见适配方案如下:

  • 对于简单数值类型的同值写入场景,优先用atomic原子操作:把tx.gas的读写都替换为atomic包的对应方法,比如写入用atomic.StoreUint64(&tx.gas, 125),读取用atomic.LoadUint64(&tx.gas),开销远小于互斥锁,也能彻底消除数据竞争。
  • 如果后续写入逻辑可能扩展得更复杂,可以用sync.Mutex或sync.RWMutex包裹读写逻辑,保证临界区互斥访问。
  • 如果这个值只需要赋值一次就不会再修改,也可以用sync.Once保证全局唯一一次写入,同样能规避并发问题。

需要注意的是,哪怕你实测这种无同步的同值写入每次都能得到预期结果,也不代表程序是合规的,编译器优化、不同CPU架构的内存模型差异都可能导致意料之外的异常,必须加同步机制才能保证程序的正确性和可移植性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 02:06:03