我正在学习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")
}
}
}
输出:
Default
Default
Program Exited
如果我注释掉默认部分
//default:
// fmt.Println("Default")
输出变为:
received one
received two
Program exited.
default
案例的存在如何改变渠道拦截的工作方式?
答案 0 :(得分:13)
这与select
语句在Go中的工作方式有关。
来自the Go documentation on select
:
如果一个或多个通信可以进行,则单个通信 可以通过统一的伪随机选择来选择。 否则,如果存在默认情况,则选择该情况。如果有 没有默认情况下,&#34;选择&#34;声明阻止至少一个 通讯可以继续。
因此,在没有默认情况下,代码将阻塞,直到某些通道中的某些数据可用。它隐含地等待其他goroutines唤醒并写入他们的频道。
当您添加默认大小写时,很可能在其他goroutines从睡眠中醒来之前已达到select
语句。
因此,由于还没有可用的数据,并且存在默认情况,因此执行默认情况。这样做了两次,只需不到1秒。所以程序最终会在任何go例程有机会唤醒并写入通道之前终止。
请注意,这在技术上是一种竞争条件;绝对不能保证循环的2次迭代将在任何go例程唤醒之前运行,因此理论上即使在默认情况下也可能有不同的输出,但实际上它极不可能。
答案 1 :(得分:2)
select
语句将阻塞,直到至少有一个案例准备就绪。 Go语言规范reads, in part:
如果一个或多个通信可以继续,则可以通过统一的伪随机选择来选择可以继续的单个通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,则“select”语句将阻塞,直到至少有一个通信可以继续。
在原始代码中,default
案例已在循环的两次迭代中准备就绪,因为在c1
或c2
上发送任何内容之前会有延迟。
删除default
案例后,select
语句必须等待c1
或c2
中的数据可用。
答案 2 :(得分:0)
Explanation:
c1 := make(chan string) // Creates a channel of type string. [Means only
strings can be sent/received on this channel]
go func() {
time.Sleep(time.Second * 1)
c1 <- "one"
}()
// func() is a goroutine [As go keyword is placed before, if no go keyword
here, then it is a simple function].
time.Sleep(time.Second * 1) // here this func() goroutine will sleep for a
second before passing a value to the channel c1.
c1 <- "one"// value "one" is passed to this channel.
select statement: Here it waits for the goroutines to complete it's task.
Once a goroutine above finishes, it matches it's case and executes the
statements.
答案 3 :(得分:-1)
https://tour.golang.org/concurrency/5
https://tour.golang.org/concurrency/6
请参阅上面给出的链接,例如执行。如果没有准备就绪,则会执行默认情况。 在golang块中选择,直到其中一个案例准备就绪。因此,删除默认值会使其他情况的执行成为可能,否则它就是在其他情况之前准备好的情况