Go race数据竞争检测

发布时间 2023-08-24 23:39:41作者: _zxq

对同一内存的竞争读写,会导致出现数据错乱,是多进程/线程编码中的常见问题。

go中提供了race工具协助识别代码中的数据竞争问题。使用起来也非常方便,设计编译的操作时加上-race即可:

go test -race xxx

go run -race xxx

go build -race xxx

go install -race xxx

这样编译出来的二进制在执行时如果检测到竞争,就可以输出报告。

还可以通过GORACE环境变量来控制race的一些行为,比如输出报告的路径,检测到报告是否退出等。

举例:

package main

import "time"

func myChan() {
	ch1 := make(chan int, 1)

	go func() {
		ch1 <- 123
	}()

	time.Sleep(1 * time.Second)
	close(ch1)
}

func main() {
	myChan()
}

执行输出:

zxq@DESKTOP-0BAPSTC:/mnt/d/go_test$ go run -race go_testrace.go
==================
WARNING: DATA RACE
Write at 0x00c000122010 by main goroutine:
  runtime.closechan()
      /usr/local/go/src/runtime/chan.go:357 +0x0
  main.myChan()
      /mnt/d/go_test/go_testrace.go:13 +0x84
  main.main()
      /mnt/d/go_test/go_testrace.go:17 +0x2f

Previous read at 0x00c000122010 by goroutine 6:
  runtime.chansend()
      /usr/local/go/src/runtime/chan.go:158 +0x0
  main.myChan.func1()
      /mnt/d/go_test/go_testrace.go:9 +0x4b

Goroutine 6 (finished) created at:
  main.myChan()
      /mnt/d/go_test/go_testrace.go:8 +0x69
  main.main()
      /mnt/d/go_test/go_testrace.go:17 +0x2f
==================
Found 1 data race(s)
exit status 66

从代码可以看出,执行过程本身是不会竞争的(sleep错开了时间),但是程序检测到了这个风险。

race检测的特点:

1.运行时检测,不是静态代码检查。

2.只有执行到的代码才能被检查出来竞争。比如一些if else的代码分支没走到,就不会检测到其中可能存在的竞争。

3.只要代码执行到就能检测出来,即使不一定出现竞争。比如上面的例子,一般是不会出现竞争态的。

4.会严重影响程序性能,可能会占用数倍的cpu和内存。所以正式环境不能上线。