选择仅从一个通道打印输出

时间:2018-03-20 08:28:08

标签: go goroutine

我正在学习Go,现在我正在使用频道。我用频道编写了一个简单的程序。我创建了两个通道,并将通道传递给一个同时调用的函数。

我的期望是从两个频道打印输出,但实际上只打印一个频道输出:

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的消息。通道应该阻塞,直到某些东西被推入其中,对吧?

4 个答案:

答案 0 :(得分:2)

您希望select同时选择两者吗?这与它的目的正好相反。来自Go Spec

  

“select”语句选择一组可能的发送或接收操作中的哪一个将继续。

     

如果一个或多个通信可以继续进行,则可以通过统一的伪随机选择来选择可以继续进行的单个通信。

如果你想从两个频道中读取,而不是让select弄清楚哪一个可以被读取(或者如果两者都可以从中读取,则选择一个伪随机),不要使用{ {1}}。请阅读以下两篇文章:

select

<强>更新

如果正如@peterSO建议的那样,你的目标是从两个频道开始阅读,从最先准备好的那个开始,我认为这样的事情是合理的方法:

msg1 := <-resp1:
fmt.Println(msg1)
msg2 := <-resp2:
fmt.Println(msg2)

你当然可以将循环硬编码为仅运行两次,但我厌恶这些东西,尽管在这个简单的例子中它并不重要。

答案 1 :(得分:1)

  

The Go Programming Language Specification

     

Select statements

     

A&#34;选择&#34;声明选择一组可能的发送或   接收操作将继续。

选择选择其中一个。例如,

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

答案 2 :(得分:0)

  

根据你的代码在select中,只要任何情况匹配将执行并且main函数将终止。这就是为什么它只打印单个通道值。   你可以通过这样做来解决这个问题:

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
  

在操场上看到:https://play.golang.org/p/T9mkfrO4wNF

答案 3 :(得分:0)

选择的工作更像是其他语言的交换机(例如:Java),您需要根据需要执行该部分N次。