Select 为什么在实际执行第一个案例时,此选择始终运行默认案例?
我正在努力更好地了解golang频道。在阅读时,我正在玩弄非阻塞发送,并想出了以下代码:Select 为什么在实际执行第一个案例时,此选择始终运行默认案例?,select,go,channels,Select,Go,Channels,我正在努力更好地了解golang频道。在阅读时,我正在玩弄非阻塞发送,并想出了以下代码: package main import ( "fmt" "time" ) func main() { stuff := make(chan int) go func(){ for i := 0; i < 5; i ++{ select { case stuff <- i:
package main
import (
"fmt"
"time"
)
func main() {
stuff := make(chan int)
go func(){
for i := 0; i < 5; i ++{
select {
case stuff <- i:
fmt.Printf("Sent %v\n", i)
default:
fmt.Printf("Default on %v\n", i)
}
}
println("Closing")
close(stuff)
}()
time.Sleep(time.Second)
fmt.Println(<-stuff)
fmt.Println(<-stuff)
fmt.Println(<-stuff)
fmt.Println(<-stuff)
fmt.Println(<-stuff)
}
虽然我知道只有0
s会被打印出来,但我真的不明白为什么第一次发送仍然会触发select的default
分支
在这种情况下,select行为背后的逻辑是什么
它只执行默认情况,因为for循环在从通道开始读取任何内容之前运行5次。每次通过时,由于无法从通道中读取任何内容,因此将进入默认情况。如果某个东西可以从通道中读取,它将执行该情况。您从不向
stuff
发送任何值,在执行fmt.Println
语句中的任何接收操作之前,您将执行所有默认情况。如果没有其他操作可以继续,则会立即执行默认值
情况,这意味着您的循环将尽快执行并返回
您希望阻止循环,因此不需要使用默认值
案例。您也不需要在末尾使用close
,因为您不依赖于关闭的通道来解除对接收的阻止或从范围
子句中断
stuff := make(chan int)
go func() {
for i := 0; i < 5; i++ {
select {
case stuff <- i:
fmt.Printf("Sent %v\n", i)
}
}
println("Closing")
}()
time.Sleep(time.Second)
fmt.Println(<-stuff)
fmt.Println(<-stuff)
fmt.Println(<-stuff)
fmt.Println(<-stuff)
fmt.Println(<-stuff)
stuff:=make(chan int)
go func(){
对于i:=0;i<5;i++{
挑选{
案例素材您的第一个案例没有执行
以下是您的程序的功能:
开始一次狂欢
尝试通过通道上的4
发送0
,所有通道都会阻塞,因为没有任何内容读取通道,因此默认设置为默认设置
同时,在主要的goroutine中,你睡了一秒钟
然后,在第二个时间过去后,尝试从通道中读取,但通道已关闭,因此每次都会得到0
要获得所需的行为,您有两个选择:
使用缓冲通道,它可以保存您发送的所有数据:
stuff := make(chan int, 5)
不要在select语句中使用default
,这将导致每次发送都等待成功
首选哪一种取决于您的目标。对于这样一个最小的示例,可能没有更好或更差。因为您使用的是非阻塞“发送”,所以0
我的示例打印的是int
的零值,而不是我认为我将发送的值。@m90:是的,无缓冲通道已经是closed,所以没有收到任何信息。我认为第一次发送实际上没有成功。+1是唯一一个非常明确地指出需要有一个读者已经在等待移交的人。其他人暗示了这一点,但不要这样解释,以免被误解。@Ray错了。发送被阻止,但select是非阻塞的。差别很大。@请帮助我,除非我没有正确理解你的评论,否则我认为你在本问答中混淆了术语“发送”。术语“发送”这里包含了select
语句和里面的所有内容。正是select
和default
使得的东西我的观点是在这个问答的上下文中使用术语“send”是误导性的。
stuff := make(chan int, 5)