数据竞争是指两个或多个 goroutine 尝试同时读取和写入同一资源。 竞争条件可能会产生看起来完全随机的错误,或者在破坏数据时永远不会出现。 原子操作和互斥锁是一种同步 goroutine 之间共享资源访问的方法。
注意:
- Goroutines 需要协调和同步。
- 当两个或多个 goroutine 试图访问同一个资源时,就会发生数据竞争。
- 原子操作和互斥锁可以提供我们需要的支持。
缓存不一致和伪共享
此内容由 Scott Meyers 在 2014 年在 Dive 的演讲中提供:
缓存不一致和伪共享注意事项:
- 线程内访问问题
- 如果您的算法没有问题,请关注伪共享方面的问题。
参考链接:
Eliminate False Sharing - Herb Sutter
The Go Memory Model
Introducing the Go Race Detector - Dmitry Vyukov and Andrew Gerrand
Detecting Race Conditions With Go - William Kennedy
Data Race Detector
图解
观察数据竞争的一个例子:
代码测试:
1、Data Race (Go Playground)
2、Atomic Increments (Go Playground)
3、Mutex (Go Playground)
4、Read/Write Mutex (Go Playground)
5、Map Data Race (Go Playground)
进阶代码测试:
Interface Based Race Condition (Go Playground)
练习:
给定以下程序,使用竞争检测器查找并纠正数据竞争。
// https://play.golang.org/p/F5DCJTZ6Lm// Fix the race condition in this program.package mainimport ("fmt""math/rand""sync""time")// numbers maintains a set of random numbers.var numbers []int// init is called prior to main.func init() {rand.Seed(time.Now().UnixNano())}// main is the entry point for the application.func main() {// Number of goroutines to use.const grs = 3// wg is used to manage concurrency.var wg sync.WaitGroupwg.Add(grs)// Create three goroutines to generate random numbers.for i := 0; i < grs; i++ {go func() {random(10)wg.Done()}()}// Wait for all the goroutines to finish.wg.Wait()// Display the set of random numbers.for i, number := range numbers {fmt.Println(i, number)}}// random generates random numbers and stores them into a slice.func random(amount int) {// Generate as many random numbers as specified.for i := 0; i < amount; i++ {n := rand.Intn(100)numbers = append(numbers, n)}}
模板 (Go Playground) | 参考答案 (Go Playground)
