Select 仅从一个通道打印输出
Select prints output from only one channel
我正在学习围棋,现在正在上频道。我用通道写了一个简单的程序。我创建了两个通道,通道被传递给一个被同时调用的函数。
我的期望是从两个通道打印输出,但实际上只打印一个通道输出:
package main
import "fmt"
func square(dat int, ch chan<- int) {
ch <- dat * dat
}
func main() {
resp1 := make(chan int)
resp2 := make(chan int)
go square(20, resp1)
go square(10, resp2)
select {
case msg1 := <-resp1:
fmt.Println(msg1)
case msg2 := <-resp2:
fmt.Println(msg2)
}
}
在每次执行期间打印来自 resp1
的消息或来自 resp2
的消息。通道应该阻塞,直到有东西被推入其中,对吗?
The Go Programming Language Specification
A "select" statement chooses which of a set of possible send or
receive operations will proceed.
Select 从一组中选择一个。例如,
package main
import "fmt"
func square(dat int, ch chan<- int) {
ch <- dat * dat
}
func main() {
resp1 := make(chan int)
resp2 := make(chan int)
go square(20, resp1)
go square(10, resp2)
// Choose one
select {
case msg1 := <-resp1:
fmt.Println(msg1)
case msg2 := <-resp2:
fmt.Println(msg2)
}
// Choose the other
select {
case msg1 := <-resp1:
fmt.Println(msg1)
case msg2 := <-resp2:
fmt.Println(msg2)
}
}
游乐场:https://play.golang.org/p/TiThqcXDa6o
输出:
100
400
您想要 select
和 select 两者?这与它的用途正好相反。来自 Go Spec:
A "select" statement chooses which of a set of possible send or receive operations will proceed.
If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection.
如果您想从两个频道读取,而不是让 select
找出准备好从哪个频道读取(或者 select 一个 pseudo-randomly 如果两个频道都可以读取来自),不要使用 select
。刚从两个阅读:
msg1 := <-resp1:
fmt.Println(msg1)
msg2 := <-resp2:
fmt.Println(msg2)
更新
如果正如@peterSO 所建议的那样,您的目标是从两个渠道读取数据,从先准备好的渠道开始,我认为这样的方法是合理的方法:
func main() {
resp1 := make(chan int)
resp2 := make(chan int)
readsWanted := 0
readsWanted += 1
go square(20, resp1)
readsWanted += 1
go square(10, resp2)
for i := 0; i < readsWanted; i++ {
select {
case msg1 := <-resp1:
fmt.Println(msg1)
case msg2 := <-resp2:
fmt.Println(msg2)
}
}
}
你当然可以 hard-code 只循环 运行 两次,但我讨厌这样的事情,虽然在这个简单的例子中它并不重要。
根据您在 select 中的代码,只要任何情况匹配都将执行并且主函数将终止。这就是它仅打印单个通道值的原因。
您可以通过执行以下操作来解决此问题:
package main
import (
"fmt"
"os"
"time"
)
func square(dat int, ch chan<- int) {
ch <- dat * dat
}
func main() {
resp1 := make(chan int)
resp2 := make(chan int)
go square(20, resp1)
go square(10, resp2)
time.Sleep(1 * time.Second)
for {
select {
case msg1 := <-resp1:
fmt.Println(msg1)
case msg2 := <-resp2:
fmt.Println(msg2)
default:
close(resp1)
close(resp2)
fmt.Println("no value recieved")
os.Exit(0)
}
}
}
输出
100
400
no value recieved
在 playground 中查看:https://play.golang.org/p/T9mkfrO4wNF
选择在另一种语言中更像是一个开关(例如:Java),您需要根据需要执行该部分 N 次。
我正在学习围棋,现在正在上频道。我用通道写了一个简单的程序。我创建了两个通道,通道被传递给一个被同时调用的函数。
我的期望是从两个通道打印输出,但实际上只打印一个通道输出:
package main
import "fmt"
func square(dat int, ch chan<- int) {
ch <- dat * dat
}
func main() {
resp1 := make(chan int)
resp2 := make(chan int)
go square(20, resp1)
go square(10, resp2)
select {
case msg1 := <-resp1:
fmt.Println(msg1)
case msg2 := <-resp2:
fmt.Println(msg2)
}
}
在每次执行期间打印来自 resp1
的消息或来自 resp2
的消息。通道应该阻塞,直到有东西被推入其中,对吗?
The Go Programming Language Specification
A "select" statement chooses which of a set of possible send or receive operations will proceed.
Select 从一组中选择一个。例如,
package main
import "fmt"
func square(dat int, ch chan<- int) {
ch <- dat * dat
}
func main() {
resp1 := make(chan int)
resp2 := make(chan int)
go square(20, resp1)
go square(10, resp2)
// Choose one
select {
case msg1 := <-resp1:
fmt.Println(msg1)
case msg2 := <-resp2:
fmt.Println(msg2)
}
// Choose the other
select {
case msg1 := <-resp1:
fmt.Println(msg1)
case msg2 := <-resp2:
fmt.Println(msg2)
}
}
游乐场:https://play.golang.org/p/TiThqcXDa6o
输出:
100
400
您想要 select
和 select 两者?这与它的用途正好相反。来自 Go Spec:
A "select" statement chooses which of a set of possible send or receive operations will proceed.
If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection.
如果您想从两个频道读取,而不是让 select
找出准备好从哪个频道读取(或者 select 一个 pseudo-randomly 如果两个频道都可以读取来自),不要使用 select
。刚从两个阅读:
msg1 := <-resp1:
fmt.Println(msg1)
msg2 := <-resp2:
fmt.Println(msg2)
更新
如果正如@peterSO 所建议的那样,您的目标是从两个渠道读取数据,从先准备好的渠道开始,我认为这样的方法是合理的方法:
func main() {
resp1 := make(chan int)
resp2 := make(chan int)
readsWanted := 0
readsWanted += 1
go square(20, resp1)
readsWanted += 1
go square(10, resp2)
for i := 0; i < readsWanted; i++ {
select {
case msg1 := <-resp1:
fmt.Println(msg1)
case msg2 := <-resp2:
fmt.Println(msg2)
}
}
}
你当然可以 hard-code 只循环 运行 两次,但我讨厌这样的事情,虽然在这个简单的例子中它并不重要。
根据您在 select 中的代码,只要任何情况匹配都将执行并且主函数将终止。这就是它仅打印单个通道值的原因。 您可以通过执行以下操作来解决此问题:
package main
import (
"fmt"
"os"
"time"
)
func square(dat int, ch chan<- int) {
ch <- dat * dat
}
func main() {
resp1 := make(chan int)
resp2 := make(chan int)
go square(20, resp1)
go square(10, resp2)
time.Sleep(1 * time.Second)
for {
select {
case msg1 := <-resp1:
fmt.Println(msg1)
case msg2 := <-resp2:
fmt.Println(msg2)
default:
close(resp1)
close(resp2)
fmt.Println("no value recieved")
os.Exit(0)
}
}
}
输出
100
400
no value recieved
在 playground 中查看:https://play.golang.org/p/T9mkfrO4wNF
选择在另一种语言中更像是一个开关(例如:Java),您需要根据需要执行该部分 N 次。