通道阻止如何在Go中运行?

use*_*896 2 select channel go

我正在学习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

这与selectGo中的语句如何工作有关.

来自Go文档select:

如果一个或多个通信可以继续,则可以通过统一的伪随机选择来选择可以继续的单个通信.否则,如果存在默认情况,则选择该情况.如果没有默认情况,则"select"语句将阻塞,直到至少一个通信可以继续.

因此,在没有默认情况下,代码将阻塞,直到某些数据在任一通道中可用.它隐含地等待其他goroutines唤醒并写入他们的频道.

当您添加默认大小写时,很可能select在其他goroutines从休眠状态唤醒之前到达该语句.

因此,由于还没有可用的数据,并且存在默认情况,因此执行默认情况.这样做了两次,只需不到1秒.因此,程序最终会在任何go例程有机会唤醒并写入通道之前终止.

请注意,这在技术上是竞争条件; 绝对不能保证循环的2次迭代将在任何go例程唤醒之前运行,因此理论上即使在默认情况下也可以具有不同的输出,但实际上它极不可能.


Mic*_*zlo 5

select语句会阻塞,直到至少一个 case 准备就绪。Go 语言规范部分内容如下:

如果可以进行一个或多个通信,则通过统一伪随机选择选择可以进行的单个通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,“select”语句会阻塞,直到至少有一个通信可以继续。

在原始代码中,default案例在循环的两次迭代中都已准备就绪,因为在c1或上发送任何内容之前存在延迟c2

删除default案例后,select语句必须等待数据在c1或 中可用c2