MST

星途 面试题库

面试题:Go语言中Go race detector检测并发问题 - 基础案例分析

请描述一个简单的Go并发程序场景,在该场景下可能出现竞态条件,并且说明如何使用Go race detector来发现这个竞态条件。同时,解释竞态条件在这个场景中具体是怎样产生的。
29.3万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

简单Go并发程序场景及竞态条件

  1. 场景描述:假设有一个银行账户,有多个并发的存钱操作。账户余额是一个共享变量,多个存钱操作同时对其进行修改。
package main

import (
    "fmt"
)

var balance int

func deposit(amount int) {
    balance = balance + amount
}

func main() {
    for i := 0; i < 10; i++ {
        go deposit(10)
    }
    fmt.Println("Final balance:", balance)
}
  1. 竞态条件产生:在上述代码中,balance = balance + amount这一操作不是原子性的。在多个goroutine同时执行deposit函数时,可能出现以下情况:
    • 一个goroutine读取了balance的值,假设为100。
    • 另一个goroutine也读取了balance的值,同样是100。
    • 第一个goroutine将读取的值加上10,得到110,然后将110写回balance
    • 第二个goroutine也将读取的值加上10,得到110,然后将110写回balance。但实际上应该是120,因为有两次存钱操作。这就是竞态条件,多个goroutine同时读写共享变量balance导致结果不正确。

使用Go race detector发现竞态条件

  1. 运行方式:在命令行中使用go run -race命令来运行程序。
    • 例如,假设上述代码保存为main.go,在终端进入该文件所在目录,执行go run -race main.go
  2. 输出示例:如果存在竞态条件,race detector会输出详细的信息,指出哪个goroutine在什么时间对哪个共享变量进行了读写操作,以及相关的堆栈信息,帮助开发者定位问题。例如:
==================
WARNING: DATA RACE
Write at 0x00c0000100d8 by goroutine 7:
  main.deposit()
      /path/to/main.go:7 +0x33
  main.main.func1()
      /path/to/main.go:13 +0x2e

Previous read at 0x00c0000100d8 by goroutine 6:
  main.deposit()
      /path/to/main.go:7 +0x23
  main.main.func1()
      /path/to/main.go:13 +0x2e

Goroutine 7 (running) created at:
  main.main()
      /path/to/main.go:13 +0x78

Goroutine 6 (finished) created at:
  main.main()
      /path/to/main.go:13 +0x78
==================
Final balance: 80
Found 1 data race(s)
exit status 66

这样就能发现并定位到代码中的竞态条件。