Select 为什么在实际执行第一个案例时,此选择始终运行默认案例?

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:

我正在努力更好地了解golang频道。在阅读时,我正在玩弄非阻塞发送,并想出了以下代码:

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)