我试图更好地了解 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)
}
Run Code Online (Sandbox Code Playgroud)
这将打印:
Default on 0
Default on 1
Default on 2
Default on 3
Default on 4
Closing
0
0
0
0
0
Run Code Online (Sandbox Code Playgroud)
虽然我确实明白只有0s 会被打印,但我不太明白为什么第一次发送仍然会触发default选择的分支?
在这种情况下,选择行为背后的逻辑是什么?
您永远不会向 发送任何值stuff,而是在执行语句中的任何接收操作之前执行所有默认情况fmt.Println。如果没有其他操作可以继续,则立即执行该default情况,这意味着您的循环将尽快执行并返回。
您想阻止循环,因此不需要案例default。您也不需要close最后的,因为您不依赖封闭通道来解锁接收或中断子句range。
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)
Run Code Online (Sandbox Code Playgroud)
https://play.golang.org/p/k2rmRDP38f
另请注意,最后的“Sent”和“Closing”行不会被打印,因为没有其他同步等待 goroutine 完成,但这不会影响此示例的结果。