Go 中的通道阻塞是如何工作的?
How does channel blocking work in 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")
}
}
}
输出:
Default
Default
Program Exited
如果我注释掉默认部分
//default:
// fmt.Println("Default")
输出变为:
received one
received two
Program exited.
default
案例的存在如何改变频道阻塞的工作方式?
select
语句阻塞,直到至少有一个案例准备就绪。 Go 语言规范 reads, in part:
If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection. Otherwise, if there is a default case, that case is chosen. If there is no default case, the "select" statement blocks until at least one of the communications can proceed.
在原始代码中,default
情况在循环的两次迭代中都准备就绪,因为在 c1
或 c2
.[=20 上发送任何内容之前存在延迟=]
删除 default
案例后,select
语句必须等待 c1
或 c2
.
中的数据可用
这与 select
语句在 Go 中的工作方式有关。
来自the Go documentation on select
:
If one or more of the communications can proceed, a single one that
can proceed is chosen via a uniform pseudo-random selection.
Otherwise, if there is a default case, that case is chosen. If there
is no default case, the "select" statement blocks until at least one
of the communications can proceed.
因此,如果没有默认情况,代码将阻塞,直到任一通道中的某些数据可用为止。它隐式等待其他 goroutines 唤醒并写入它们的通道。
当你添加default case时,很可能在其他goroutines从休眠中醒来之前到达select
语句。
因此,由于(还)没有可用数据,并且存在默认情况,因此执行默认情况。这样做两次,用时不到 1 秒。因此程序在任何 go 例程有机会唤醒并写入通道之前终止。
请注意,这在技术上是一种竞争条件;绝对不能保证循环的 2 次迭代将 运行 在任何 go 例程唤醒之前,因此理论上即使在默认情况下也可能有不同的输出,但实际上它非常不太可能。
https://tour.golang.org/concurrency/5
https://tour.golang.org/concurrency/6
请参阅上面给出的链接以执行示例。如果没有其他案例准备就绪,则执行默认案例。
select 在 golang 中阻塞,直到其中一个案例准备就绪。因此,删除默认值可以执行其他情况,否则它是先于其他情况准备好的
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.
我正在学习 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
案例的存在如何改变频道阻塞的工作方式?
select
语句阻塞,直到至少有一个案例准备就绪。 Go 语言规范 reads, in part:
If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection. Otherwise, if there is a default case, that case is chosen. If there is no default case, the "select" statement blocks until at least one of the communications can proceed.
在原始代码中,default
情况在循环的两次迭代中都准备就绪,因为在 c1
或 c2
.[=20 上发送任何内容之前存在延迟=]
删除 default
案例后,select
语句必须等待 c1
或 c2
.
这与 select
语句在 Go 中的工作方式有关。
来自the Go documentation on select
:
If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection. Otherwise, if there is a default case, that case is chosen. If there is no default case, the "select" statement blocks until at least one of the communications can proceed.
因此,如果没有默认情况,代码将阻塞,直到任一通道中的某些数据可用为止。它隐式等待其他 goroutines 唤醒并写入它们的通道。
当你添加default case时,很可能在其他goroutines从休眠中醒来之前到达select
语句。
因此,由于(还)没有可用数据,并且存在默认情况,因此执行默认情况。这样做两次,用时不到 1 秒。因此程序在任何 go 例程有机会唤醒并写入通道之前终止。
请注意,这在技术上是一种竞争条件;绝对不能保证循环的 2 次迭代将 运行 在任何 go 例程唤醒之前,因此理论上即使在默认情况下也可能有不同的输出,但实际上它非常不太可能。
https://tour.golang.org/concurrency/5
https://tour.golang.org/concurrency/6
请参阅上面给出的链接以执行示例。如果没有其他案例准备就绪,则执行默认案例。 select 在 golang 中阻塞,直到其中一个案例准备就绪。因此,删除默认值可以执行其他情况,否则它是先于其他情况准备好的
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.