我正在学习Go语言.这是我遇到的一个例子.有人可以解释一下这里发生了什么吗?
package main
import "time"
import "fmt"
func main() {
c1 := make(chan string)
c2 := make(chan string)
go func() {
time.Sleep(time.Second * 1)
c1 <- "one"
}()
go func() {
time.Sleep(time.Second * 2)
c2 <- "two"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
default:
fmt.Println("Default")
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
Default
Default
Program Exited
Run Code Online (Sandbox Code Playgroud)
如果我注释掉默认部分
//default:
// fmt.Println("Default")
Run Code Online (Sandbox Code Playgroud)
输出变为:
received one
received two
Program exited.
Run Code Online (Sandbox Code Playgroud)
default
案例的存在如何改变频道阻止的工作方式?
Fil*_*ves 18
这与select
Go中的语句如何工作有关.
来自Go文档select
:
如果一个或多个通信可以继续,则可以通过统一的伪随机选择来选择可以继续的单个通信.否则,如果存在默认情况,则选择该情况.如果没有默认情况,则"select"语句将阻塞,直到至少一个通信可以继续.
因此,在没有默认情况下,代码将阻塞,直到某些数据在任一通道中可用.它隐含地等待其他goroutines唤醒并写入他们的频道.
当您添加默认大小写时,很可能select
在其他goroutines从休眠状态唤醒之前到达该语句.
因此,由于还没有可用的数据,并且存在默认情况,因此执行默认情况.这样做了两次,只需不到1秒.因此,程序最终会在任何go例程有机会唤醒并写入通道之前终止.
请注意,这在技术上是竞争条件; 绝对不能保证循环的2次迭代将在任何go例程唤醒之前运行,因此理论上即使在默认情况下也可以具有不同的输出,但实际上它极不可能.