企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# **竞态(Race conditions)** `pipeline.go`并不完美,它包含一个逻辑错误,在并发术语中称为**竞态**。这可以通过执行以下命令来揭示: ```shell $ go run -race pipeline.go 1 10 2 2 ================== WARNING: DATA RACE Write at 0x00000122bae8 by goroutine 7: main.second() /Users/mtsouk/ch09/pipeline.go:34 +0x15c Previous read at 0x00000122bae8 by goroutine 6: main.first() /Users/mtsouk/ch09/pipeline.go:21 +0xa3 Goroutine 7 (running) created at: main.main() /Users/mtsouk/ch09/pipeline.go:72 +0x2a1 Goroutine 6 (running) created at: main.main() /Users/mtsouk/ch09/pipeline.go:71 +0x275 ================== 2 The sum of the random numbers is 2. Found 1 data race(s) exit status 66 ``` 这里的问题是,当`first()`函数读取CLOSEA变量时,执行`second()`函数的`goroutine`可能会更改CLOSEA变量的值。因为先发生什么和后发生什么是不确定的,所以被认为是竞态。为了修正这个竞态条件,我们需要使用一个信号通道和`select`关键字。 >Tip:第十章会有更多`select`的介绍。 `diff(1)`命令会揭示新代码`plNoRace.go`和之前代码的区别: ```bash $ diff pipeline.go plNoRace.go 14a15,16 > var signal chan struct{} > 21c23,24 < if CLOSEA { --- > select { > case <-signal: 23a27 > case out <- random(min, max): 25d28 < out <- random(min, max) 31d33 < fmt.Print(x, " ") 34c36 < CLOSEA = true --- > signal <- struct{}{} 35a38 > fmt.Print(x, " ") 61d63 < 66a69,70 > signal = make(chan struct{}) > ``` `plNoRace.go`的正确性可以通过如下命令验证: ```bash $ go run -race plNoRace.go 1 10 8 1 4 9 3 The sum of the random numbers is 25. ```