golang 中的 race
基本就是抄自 golang blog 了
背景
数据竞争是所有并发程序都需要注意的问题,尤其是像 golang 这种原生支持并发的程序.
在 golang 发行到 1.1 版本时自带 race detector, 用来找到 go 代码中的数据竞争状态。
race detector 基于 google 开源的 C/C++ 库 ThreadSanitizer runtime library, 在集成到 golang 中后,就发现了标准库中 42 处竞争状态。
工作原理
race detector 集成到了 golang 的工具链中。在命令行使用 -race 选项,编译器就会记录代码中所有的 memory access, 包括访问方式和时间。运行时库观察所有对共享变量的未同步访问,每当发现这样的行为,就会输出一个 warning, 具体实现细节可见 链接
因为依赖于运行时库的设计,race detector 只能在运行时做数据竞争状态的检查。但是在开启 race detector 后,cpu 的负载将为原来不启用 race detector 的 10 倍。所以不可能在线上应用中启用 race detector. 但是在生产环境中使用的一种情况是,在许多线上的 servers 中,只有一个 server 的应用启用了 race detector, 对业务影响不大。
使用 race detector
race detector 集成到了 golang 中的工具链中,只要命令行中设置 -race 选项就可以使用 race detector
1 | go test -race |
示例代码
1 | func main() { |
在这段代码看不出来有什么数据竞争带代码,运行起来也似乎没什么问题,但是在极偶尔的情况下第 6 行代码会出现 nil 指针引用的情况,打开 race detector 发现在 4 行代码的调用 time.sleep 会开启一个 goroutine 来执行传入的 func, func 闭包对 main 中的 t 进行了读写,但是 t 的赋值是在 main 中完成的,不一定是在 goroutine 开启之前,所以可能会发生 nil 指针引用的情况。
这段代码要修正把对 t 的读写全部放在 main 中就好。