为了学习,我使用这段代码与goroutines一起玩。我无法得到不同的东西:
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan string) // <A>
ch2 := make(chan string) // <B>
go test(ch1, ch2)
ch1 <- "hi" // <C>
ch2 <- "bye" // <D>
fmt.Scanln()
}
func test(ch1 chan string, ch2 chan string) {
timeout := time.After(time.Second * 2) // <E>
defer func() { fmt.Println("returning") }()
for {
select {
case s := <-ch1:
fmt.Println(s, "1")
ch2 <- "ch2"
fmt.Println("after 1")
case s := <-ch2:
fmt.Println(s, "2")
ch1 <- "ch1"
fmt.Println("after 2")
case <-timeout:
fmt.Println("timed out")
return
}
}
}
如果我按原样运行代码,我总是得到:
嗨1 致命错误:所有goroutines都睡着了 - 死锁!
关键是程序正好等待 E 部分的指定持续时间。我的意思是,如果我增加睡眠时间,那个致命的错误会在经过那段时间之后出现。所以第一个问题是:
1-究竟发生了什么?谁能解释一下这种行为?
1-1-为什么代码总是打印"hi 1"
?我已经读过select语句随机从准备好的频道中选择,为什么总是"hi 1"
?如果我交换 C 和 D ,则会始终打印"bye 2"
。
1-2-为什么程序会等待那段时间然后发生死锁?
现在假设我将通道缓冲在 A 和 B 中,大小为1,即:
ch1 := make(chan string, 1) // <A>
ch2 := make(chan string, 1) // <B>
现在每次运行程序时,它会随机打印"hi 1"
和"bye 2"
(只有一次)并永远等待(如果我点击进入程序退出,在main函数中编码)
2-现在发生了什么?请解释一下。
最后,如果我将缓冲区大小设置为2(或更多):
ch1 := make(chan string, 2) // <A>
ch2 := make(chan string, 2) // <B>
程序按预期运行,并依次打印"hi 1"
和"bye 2"
,直到经过 E 部分编码的时间为止:
ch1 1
after 1
ch2 2
after 2
ch1 1
after 1
ch1 1
after 1
ch2 2
.
.
.
timed out
returning
我认为这里的一切都很清楚,因为通道的缓冲大小合适,一切都按预期工作。
答案 0 :(得分:0)
1.1。你首先发送ch1。 select循环从可以运行的所有路径中随机选择。第二种情况无法运行,因为在ch1中“hi”之前,ch2中没有任何内容。
1.2。你的超时。
ch1<-"hi"
和`ch2&lt; - “by2”,并且select可以选择。