两个 goroutine,一个输出奇数,一个输出偶数,交替输出,最终达到顺序输出的目的。
其中 B 协程运行到最后的时候,如果不做特殊的处理,继续向 A 通道写入数据,会导致 A 通道死锁。
感到很奇怪,为什么会这样? A 通道这时候是没有数据的,为什么不让写?
package main
import (
"fmt"
)
func main() {
// 创建 3 个 channel,A,B 和 Exit
A := make(chan bool)
B := make(chan bool)
Exit := make(chan bool)
go func() {
// 如果 A 通道是 true,我就执行
for i := 1; i <= 10; i += 2 {
if ok := <-A; ok {
fmt.Println("A 输出", i)
B <- true
}
}
}()
go func() {
defer func() { Exit <- true }() // 这个协程的活干完之后,向主 goroutine 发送信号
// 如果 B 通道是 true,我就执行
for i := 2; i <= 10; i += 2 {
if ok := <-B; ok {
fmt.Println("B 输出", i)
if i != 10 { // 如果 i 等于 10 了,就不要再向 A 通道写数据了,否则将导致 A 通道死锁,至于为什么,坦白说我很疑惑
A <- true
}
}
}
}()
A <- true // 启动条件
<-Exit // 结束条件
}
1
darrh00 2021-06-03 19:01:53 +08:00 1
第二个 goroutine 运行到 i = 10 的时候,第一个 goroutine 中的 for 循环已经结束退出了,因此 A 通道再也没有了接收者,而第二个 goroutine 里还继续向 A 通道写数据,当然就出错了。
|
2
SteinsGate 2021-06-03 19:03:13 +08:00 via Android
因为第一个退出了,无缓冲区通道,没人消费 A,卡在了 A <- true
|
4
v2defy OP @SteinsGate 谢谢大佬,懂了
|
5
GTim 2021-06-03 19:17:33 +08:00
给你换种方式输出结果你就知道了
```go package main import ( "fmt" ) func main() { // 创建 3 个 channel,A,B 和 Exit A := make(chan bool) B := make(chan bool) Exit := make(chan bool) go func() { // 如果 A 通道是 true,我就执行 for i := 1; i <= 10; i += 2 { if ok := <-A; ok { fmt.Printf("-> A(%d)", i) B <- true } } fmt.Print("===bye==") }() go func() { defer func() { Exit <- true }() // 这个协程的活干完之后,向主 goroutine 发送信号 // 如果 B 通道是 true,我就执行 for i := 2; i <= 10; i += 2 { if ok := <-B; ok { fmt.Printf("-> B(%d)", i) //if i != 10 { // 如果 i 等于 10 了,就不要再向 A 通道写数据了,否则将导致 A 通道死锁,至于为什么,坦白说我很疑惑 A <- true //} } } fmt.Print("===bye==") }() fmt.Print("|") A <- true // 启动条件 <-Exit // 结束条件 } ``` 输出结果如下 ``` |-> A(1)-> B(2)-> A(3)-> B(4)-> A(5)-> B(6)-> A(7)-> B(8)-> A(9)===bye==-> B(10)fatal error: all goroutines are asleep - deadlock! ``` 原因是不带缓冲区的 chan 写入时立刻会被堵塞。看看官方怎么对无缓冲区 chan 的描述就知道了 |
7
george404 2021-06-04 09:31:52 +08:00
还有,我建议用 waitgroup 来同步不同的 thread. 这样看上去也比较清晰。个人建议啦。
|