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

Go语言中Data Race与Race Condition的区别是什么?

Data Race 和 Race Condition 的核心差异及Go示例

一、基本定义

1. Race Condition(竞态条件)

当程序的最终结果依赖于多个goroutine/线程的执行顺序,而这个顺序无法被控制时,就会出现竞态条件。这是一种逻辑层面的问题,不一定会涉及内存访问的冲突。

2. Data Race(数据竞争)

当两个或多个goroutine同时访问同一块内存,且至少有一个操作是写操作,同时没有任何同步机制来协调这些访问时,就会发生数据竞争。这是内存访问层面的错误,Go的竞争检测器(race detector)可以直接检测到这类问题。

一句话总结:所有数据竞争都是竞态条件的一种,但并非所有竞态条件都是数据竞争。

二、代码示例

1. 无Data Race的Race Condition

下面的例子没有内存访问冲突,但结果完全依赖goroutine的执行顺序:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	var count int

	wg.Add(2)
	// Goroutine 1:先加1再减1
	go func() {
		defer wg.Done()
		count++
		count--
	}()

	// Goroutine 2:直接把count设为0
	go func() {
		defer wg.Done()
		count = 0
	}()

	wg.Wait()
	fmt.Println("最终count值:", count)
}

运行这个程序,你可能得到0、1甚至-1的结果:

  • 如果Goroutine2先执行count=0,接着Goroutine1完成加减,结果是0;
  • 如果Goroutine1先完成加减,再轮到Goroutine2赋值0,结果是0;
  • 如果Goroutine1刚执行完count++(此时count=1),Goroutine2就把count设为0,接着Goroutine1执行count--,结果就是-1。

这里每个内存操作都是原子性的(32/64位系统上,对应位数的int赋值、加减是原子操作),所以没有Data Race,但因为执行顺序不可控,出现了Race Condition。

2. Data Race 示例

最典型的就是多个goroutine同时读写同一个变量,完全不加同步:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	var count int

	wg.Add(1000)
	for i := 0; i < 1000; i++ {
		go func() {
			defer wg.Done()
			count++ // 1000个goroutine同时写count,无同步
		}()
	}

	wg.Wait()
	fmt.Println("最终count值:", count)
}

运行这个程序,结果肯定小于1000。因为count++不是原子操作,它拆成了三步:读当前值、加1、写回。多个goroutine同时执行时,会互相覆盖写操作,这就是Data Race。用go run -race main.go就能直接检测到这个问题。

三、关键差异总结

  • Data Race:属于内存访问冲突,是可被工具检测的具体错误,必须通过同步手段(mutex、channel、atomic包等)解决。
  • Race Condition:属于逻辑依赖执行顺序的问题,可能是业务逻辑设计缺陷,不一定存在内存冲突,需要通过调整逻辑或增加同步来规避。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 14:15:46