1.数据竞态
Blocking(阻塞):是指多个(大于或等于2 个)goroutine在执行过程中,因争夺资源而造成的一种相互等待的现象。
Race(竞态):数据竞态是指多个(大于或等于2 个)goroutine在执行过程中,读写相同数据的情况,必须存在至少一方写。另外,如果所有 goroutine 都只是进行读操作,那将不会构成数据争用
不同读写协程的执行时机不同导致结果出乎意料的结果
2.监测数据竞态
go run -race main.go
go build -race main.go
go test -race a_test.go
go install -race main.go
3.修复 Data Races的4种方式
A、等待组(sync.WaitGroup)
使用WaitGroup来Blocking(阻塞),控制读写协程的执行顺序
B、通道channel,也就是消息机制
使用Channel来Blocking(阻塞),控制读写协程的执行顺序
C、原子函数 (sync/atomic)
一个或者多个操作在 CPU 执行的过程中不被中断的特性,称为原子性(atomicity) 。这些操作对外表现成一个不可分割的整体,他们要么都执行,要么都不执行,外界不会看到他们只执行到一半的状态。
D、互斥锁(sync.Mutex)
sync.Mutex是Go标准库中常用的一个排外锁。当一个 goroutine 获得了这个锁的拥有权后, 其它请求锁的 goroutine 就会阻塞在 Lock 方法的调用上,直到锁被释放。
互斥锁是用来保护一段逻辑,原子操作用于对一个变量的更新保护。
底层实现: Mutex由操作系统的调度器实现,而atomic包中的原子操作则由底层硬件指令直接提供支持,这些指令在执行的过程中是不允许中断的,因此原子操作可以在lock-free的情况下保证并发安全,并且它的性能也能做到随CPU个数的增多而线性扩展。
4.for循环相关的数据竞态
for循环中go协程作用域,导致和期望数据不一致
- goroutine加参数
- 将for循环中的变量作用域缩小到goroutine中
for goroutine 中的执行顺序是 无序的 ,业务中做的时候需要了解
参考:
https://mp.weixin.qq.com/s/hWENZOB70Y6Vz2TKdJEUmg
https://cloud.tencent.com/developer/article/1882225