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

时间:2015-09-12 11:50:14

标签: select go channel

我正在学习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案例的存在如何改变渠道拦截的工作方式?

4 个答案:

答案 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案例已在循环的两次迭代中准备就绪,因为在c1c2上发送任何内容之前会有延迟。

删除default案例后,select语句必须等待c1c2中的数据可用。

答案 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块中选择,直到其中一个案例准备就绪。因此,删除默认值会使其他情况的执行成为可能,否则它就是在其他情况之前准备好的情况