golang中go race使用
多线程/协程中的线程安全分析
在项目中,使用多线程会导致线程安全问题,引发bug发生,如果是运行中发生问题更难定位
常见的情况有两种 死锁 竞争,例如
死锁
编译打包时,死锁发生 go run 会直接报错
两个或两个以上的进程(或线程)在执行过程中,因争夺资源而造成的一种相互等待的现象。
竞争
当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件。
Go 的命令中,-race参数用于启用竞态检测器(Race Detector)
虽然说,我们能够通过规范的代码避免死锁,sync.Mutex和channel规避线程安全,但总该有个监测的过程,以防万一
go reac就是帮我们干这个事情的,切记,建议在测试环境中使用!!!
它能帮助你发现程序中是否存在多个 goroutine 同时读写同一个变量而没有同步机制的问题
使用方式例如
go test -race mypkg go run -race mysrc.go go build -race mycmd go install -race mypkg
使用示例
我们故意写一段,线程危险的程序
package main
import (
"fmt"
"time"
)
var counter int = 0
func main() {
go func() {
for i := 0; i < 100; i++ {
counter++ // 写操作
}
}()
go func() {
for i := 0; i < 100; i++ {
counter-- // 写操作
}
}()
time.Sleep(10 * time.Millisecond) // 等待 goroutine 执行(不推荐的方式,仅用于演示)
fmt.Println("Final counter:", counter)
}
使用go run -race main.go调试
这里已经很清晰的将分析报告、代码行数输出
==================
WARNING: DATA RACE
Read at 0x000001d6bd90 by goroutine 7:
main.main.func2()
/Applications/www/blog-code/main.go:19 +0x2c
Previous write at 0x000001d6bd90 by goroutine 6:
main.main.func1()
/Applications/www/blog-code/main.go:13 +0x44
Goroutine 7 (running) created at:
main.main()
/Applications/www/blog-code/main.go:17 +0x33
Goroutine 6 (finished) created at:
main.main()
/Applications/www/blog-code/main.go:11 +0x27
==================
==================
WARNING: DATA RACE
Read at 0x000001d6bd90 by main goroutine:
main.main()
/Applications/www/blog-code/main.go:24 +0x77
Previous write at 0x000001d6bd90 by goroutine 7:
main.main.func2()
/Applications/www/blog-code/main.go:19 +0x44
Goroutine 7 (finished) created at:
main.main()
/Applications/www/blog-code/main.go:17 +0x33
==================
Final counter: 0
Found 2 data race(s)
exit status 66
我们将代码修改一些,加上安全锁
// race_fixed.go
package main
import (
"fmt"
"sync"
)
var (
counter int
mu sync.Mutex
)
func main() {
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
for i := 0; i < 100; i++ {
mu.Lock()
counter++
mu.Unlock()
}
}()
go func() {
defer wg.Done()
for i := 0; i < 100; i++ {
mu.Lock()
counter--
mu.Unlock()
}
}()
wg.Wait()
fmt.Println("Final counter:", counter) // 应该输出 0
}
再次执行 go run -race main.go 将没有警告输出
Final counter: 0
注意
- 不要用于生产环境
- -race 会显著降低程序性能(约 2–10 倍变慢),内存占用也更高
- windows下需有
gcc环境,且与go的版本匹配,例如 go.1.22 使用 gcc version 8.1 会有异常发生,推荐使用 gcc14.2
到此这篇关于golang中go race使用的文章就介绍到这了,更多相关go race使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!


最新评论