【发布时间】:2021-04-06 15:46:35
【问题描述】:
一个 select 阻塞直到它的一个 case 可以运行,然后它执行那个 case。
我在测试select案例,结果出乎意料:
func main() {
channel1 := make(chan string)
channel2 := make(chan string)
go func() {
for i := 0; i < 5; i++ {
channel1 <- "I'll print every 100ms"
time.Sleep(time.Millisecond * 100)
}
}()
go func() {
for i := 0; i < 5; i++ {
channel2 <- "I'll print every 1s"
time.Sleep(time.Second * 1)
}
}()
for i := 0; i < 5; i++ {
select {
case message1 := <-channel1:
fmt.Println(message1)
case message2 := <-channel2:
fmt.Println(message2)
}
}
}
大部分时间它打印1s,这与goroutines完美。但是一旦它在100ms之间打印1s:
/*
$ go run .
I'll print every 1s
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
$ go run .
I'll print every 1s
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
$ go run .
I'll print every 1s
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
$ go run .
I'll print every 1s
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
$ go run . # WHY 1s IS EXCECUTED IN BETWEEN?
I'll print every 100ms
I'll print every 1s # HERE?
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
$ go run .
I'll print every 1s
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
$ go run .
I'll print every 1s
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
$ go run .
I'll print every 1s
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
*/
根据select 声明,我预计它会产生结果,因为它首先选择了100ms:
/*
# Either
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
I'll print every 1s
# Or
I'll print every 100ms
I'll print every 1s
# But not:
I'll print every 100ms
I'll print every 1s
I'll print every 100ms
I'll print every 100ms
I'll print every 100ms
*/
或者,我误解了select 声明?
【问题讨论】:
-
super's answer 尽其所能。当两种情况都准备好时,将选择其中一种。由于前两个 goroutine 中的 sleep 语句发生在发送之后,因此您不能期望来自 channel2 的接收发生在从 channel1 接收之前。此外,因为您使用的是无缓冲通道,并且接收总数 (5) 与发送总数 (10) 不匹配,所以在
main终止时,您正在泄漏一到两个 goroutine。在这样一个简单的程序中没什么大不了的,但总的来说值得注意。
标签: go