golang工具race - 检测非法竞态访问数据

简介

非法竞态访问数据的常见场景是无任何同步保护下并行读写同一份数据。读写指有写的同时还有其它读或者写,都是读不算。

golang官方提供了非法竞态访问数据的检测手段。使用起来非常简单,不需要额外安装工具。
方法为在编译时添加-race参数。
该方法是运行时检测,而非静态代码检测。跑test和跑程序时都可以添加该参数来检测。

如何使用

1
2
3
4
5
6
# 编译出带检测的程序
$go build -race
# 跑test时带检测功能
$go test -race
# 直接允许也可以添加
$go run -race main.go

举例

模拟非法竞态访问数据的demo如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import "fmt"

func main() {
c := make(chan bool)
m := make(map[string]string)
go func() {
m["1"] = "a" // First conflicting access.
c <- true
}()
m["2"] = "b" // Second conflicting access.
<-c
for k, v := range m {
fmt.Println(k, v)
}
}

demo运行输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
==================
WARNING: DATA RACE
Write at 0x00c00008a180 by goroutine 6:
runtime.mapassign_faststr()
/usr/local/go/src/runtime/map_faststr.go:190 +0x0
main.main.func1()
/Users/chef/Documents/sss/gopath/src/github.com/q191201771/snippet/demo1/main.go:9 +0x5d

Previous write at 0x00c00008a180 by main goroutine:
runtime.mapassign_faststr()
/usr/local/go/src/runtime/map_faststr.go:190 +0x0
main.main()
/Users/chef/Documents/sss/gopath/src/github.com/q191201771/snippet/demo1/main.go:12 +0xc9

Goroutine 6 (running) created at:
main.main()
/Users/chef/Documents/sss/gopath/src/github.com/q191201771/snippet/demo1/main.go:8 +0x9a
==================
2 b
1 a
Found 1 data race(s)

运行时额外消耗

一般来说,内存会增加5到10倍,执行时间增加2到20倍。
个人建议在开发环境对性能要求不高时可默认打开race,在项目达到一定阶段,也可以打开race跑一些压测做检查。

参考链接

本文完,作者yoko,尊重劳动人民成果,转载请注明原文出处: https://pengrl.com/p/41755/

0%