Go这样检测Data Race让并发程序又简单了许多

大家好,我是极客老墨。 写并发代码最怕什么?不是死锁,不是性能问题,而是那些偶尔才出现、难以复现的诡异 bug。这些 bug 的罪魁祸首往往就是 Data Race(数据竞争)。 什么是 Data Race? Data Race 的定义很简单:当两个或多个 goroutine 同时访问同一个变量,且至少有一个在写入时,就会发生数据竞争。 这就像两个人同时在一张纸上写字,最后的结果可能是谁的字都不完整,或者干脆就是一团乱码。 举个例子: 1var counter int 2 3func increment() { 4 counter++ // 看起来是一行代码,实际上是三个操作:读取、加1、写入 5} 6 7func main() { 8 go increment() 9 go increment() 10 time.Sleep(time.Second) 11 fmt.Println(counter) // 结果可能是 1,也可能是 2 12} 这段代码看起来没问题,但 counter++ 并不是原子操作。两个 goroutine 可能同时读到 0,然后都写入 1,最终结果就是 1 而不是期望的 2。 顺便说一句,Data Race 和 Race Condition 是两个不同的概念,很多人会混淆。我之前翻译过一篇文章专门讨论这个问题,感兴趣可以看看。 Go 内存模型定义了 Happens-Before 规则来保证程序执行的顺序性,这和 Java 内存模型的思路类似。但光有规则还不够,Go 从 1.1 版本开始提供了 Race Detector,让我们能在运行时检测出这些问题。 ...

2026-03-03 · 5 min · 870 words · 老墨

Data Race vs Race Condition

原文地址: https://blog.regehr.org/archives/490, 翻译并略作改动。 竞态条件(race Condition)是当事件的时间或顺序影响程序的正确性时发生的缺陷。一般来说,需要某种外部计时或排序非确定性来产生竞态条件;典型的例子有上下文切换、操作系统信号、多处理器上的内存操作和硬件 中断。 当程序中有两次内存访问时,就会发生数据竞争(Data Race): 目标为同一内存位置 由两个线程同时执行 不是读取操作 不是同步操作 上边这个定义来自微软研究院的 Sebastian Burckhardt。该定义的两个方面需要注意: “同时”意味着没有像锁这样的东西强制一个操作在另一个操作之前或之后发生。 “不是同步操作”是指程序可能包含特殊的内存操作,例如用于实现锁的操作,这些操作本身并不同步。 在实践中,它们两者存在相当大的重合:许多 Race Condition 是由 Data Race 引起的,并且许多 Data Race 导致 Race Condition。另一方面,两者也可以相互独立,可能产生没有 Data Race 的 Race Condition,也可能产生没有 Race Condition 的 Data Race。 让我们从一个在两个银行账户之间转移资金的简单函数开始: transfer1 (amount, account_from, account_to) { if (account_from.balance < amount) return NOPE; account_to.balance += amount; account_from.balance -= amount; return YEP; } 当然,这并不是银行真正转移资金的方式,但这个例子非常有用。我们知道,账户余额应该是非负的,并且转移之后不能凭空创造(多出)或损失(丢失)金钱。当在没有外部同步的情况下从多个线程调用时,该函数会产生 Data Race(多个线程可以同时尝试更新帐户余额)和 Race Condition(在并行上下文中它将创造或损失金钱)。 我们可以尝试这样修复它: transfer2 (amount, account_from, account_to) { atomic { bal = account_from.balance; } if (bal < amount) return NOPE; atomic { account_to.balance += amount; } atomic { account_from.balance -= amount; } return YEP; } 这里的“atomic”(原子性)是由语言运行时实现的,也许简单地通过在原子块开始时获取线程互斥体(Mutex)并在结束时释放它,也许使用某种事务(Transaction),或者也许通过禁用中断 —— 出于示例的目的,只要 atomic 块内的代码以原子方式执行就能解决竞争问题。 ...

2024-06-18 · 2 min · 235 words · 老墨