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

Go代码是否存在竞态条件?为何go run -race未检测到?

为什么这段Go代码不会被检测出竞态条件?

先看这段核心代码:

func main() {
    m := map[string]int{
        "foo": 42,
        "bar": 1337,
    }

    go func() {
        time.Sleep(1 * time.Second)
        tmp := map[string]int{
            "foo": 44,
            "bar": 1339,
        }

        m = tmp
    }()

    for {
        val := m["foo"]
        fmt.Println(val)
    }
}

关键原因:仅对map引用做原子性赋值,未触碰同一map的内部结构

Go里的map是引用类型,变量m本质是指向map底层数据结构的指针。这段代码的操作逻辑是:

  • 子协程只是把m重新赋值为指向全新map的指针,完全没有修改原map的内部键值对
  • 主协程的循环只是读取m当前指向的map里的"foo"值,同样没有修改原map

而Go竞态检测器的核心检测逻辑是是否存在对同一内存地址的并发读写:

  • 原map的内存地址在主协程读取时,没有被任何协程修改(子协程只是替换了m的指向,原map本身没被操作)
  • 指针大小的赋值操作在Go里是原子性的,不会出现半完成的中间状态,主协程要么读到旧map的值,要么读到新map的值,不会出现混乱

所以主、子协程并没有同时操作同一块内存,竞态检测器自然不会报错。

额外提醒

这种写法是安全的,但如果改成在子协程里直接修改原map的键值(比如m["foo"] = 44),必然会触发竞态检测报错——因为这属于对同一map底层结构的并发读写操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:42:06