在Golang中同时从多个通道读取数据

huangapple go评论72阅读模式
英文:

Reading from multiple channels simultaneously in Golang

问题

我是新手学习Golang。我正在尝试弄清楚如何在Golang中创建一个任意到一的通道,设置如下:

假设我有两个并发执行的goroutine numgen1和numgen2,它们分别向通道num1和num2写入数字。我想在一个新的进程addnum中将来自numgen1和numgen2的数字相加。我尝试了以下代码:

func addnum(num1, num2, sum chan int) {
    done := make(chan bool)
    go func() {
        n1 := <- num1
        done <- true
    }()
    n2 := <- num2
    <- done
    sum <- n1 + n2
}

但是这个代码似乎是错误的。请问有人可以给我一些想法吗?

非常感谢你的帮助。

英文:

I am new to Golang. Right now I am trying to figure out how to make an any-to-one channel in Golang, where the setup is as follows:

say I have two goroutines numgen1 and numgen2 executing concurrently and writing numbers to channels num1 resp. num2. I would like to add the numbers sent from numgen1 and numgen2 in a new process, addnum. I have tried something like this:

func addnum(num1, num2, sum chan int) {
    done := make(chan bool)
    go func() {
        n1 := &lt;- num1
        done &lt;- true
    }()
        n2 := &lt;- num2
        &lt;- done
    sum &lt;- n1 + n2
}

but this seems sadly incorrect. Could someone please give me some ideas?

Thank you very much for your help.

答案1

得分: 19

根据您的要求,您可能需要在每次迭代中同时读取两个通道(类似于“zip”函数)。您可以使用select语句来实现,类似于user860302的回答中所示:

func main() {

  c1 := make(chan int)
  c2 := make(chan int)
  out := make(chan int)

  go func(in1, in2 <-chan int, out chan<- int) {
    for {
      sum := 0
      select {
      case sum = <-in1:
        sum += <-in2

      case sum = <-in2:
        sum += <-in1
      }
      out <- sum
    }
  }(c1, c2, out)
}

这段代码会一直运行。我喜欢使用关闭输入通道的方式来终止类似这样的goroutine。在这种情况下,您需要等待两个通道都关闭,然后在终止之前close(out)

提示:请注意在goroutine的形式参数中使用方向性通道。这样编译器在您编写代码时可以捕捉更多的错误。愉快编程!

英文:

Depending on your requirements, you may need to read both of the channels for every iteration (i.e. a sort-of 'zip' function). You can do this with a select, similarly to user860302's answer:

func main() {

  c1 := make(chan int)
  c2 := make(chan int)
  out := make(chan int)

  go func(in1, in2 &lt;-chan int, out chan&lt;- int) {
    for {
      sum := 0
      select {
      case sum = &lt;-in1:
        sum += &lt;-in2

      case sum = &lt;-in2:
        sum += &lt;-in1
      }
      out &lt;- sum
    }
  }(c1, c2, out)
}

This runs forever. My preferred way to terminate goroutines like this one is to close the input channels. In this case you would need to wait for both to close, then close(out) before terminating.

Tip: note the use of directional channels as goroutine formal parameters. The compiler catches more mistakes when you write it this way. Happiness!

答案2

得分: 8

最简单的答案是:

func addnum(num1, num2, sum chan int) {
  n1 := <- num1
  n2 := <- num2
  sum <- n1 + n2
}

由于需要同时使用num1num2进行计算,否则就没有意义。毕竟,有两种可能的执行顺序:

  1. num1生成一个数字,然后是num2
  2. num2生成一个数字,然后是num1

在第一种情况下,我们的通道读取与执行顺序完全对应。在第二种情况下,我们的第一次读取将阻塞,直到num1最终生成一个数字;第二次读取将立即完成,因为num2通道已经有一个数字。

如果你想了解更多关于Go中通道的知识,我建议你查看http://godoc.org/github.com/thomas11/csp -- 这是一个使用Go编写的Hoare的CSP示例集合。

英文:

The simplest answer would be

func addnum(num1, num2, sum chan int) {
  n1 := &lt;- num1
  n2 := &lt;- num2
  sum &lt;- n1 + n2
}

Since you need both num1 and num2 to do the calculation, it makes no sense to do it otherwise. After all, there are two possible execution orders:

  1. num1 generates a number, followed by num2
  2. num2 generates a number, followed by num1

In the first case, our channel reads correspond exactly to the execution order. In the second case, our first read will block until num1 has finally produced a number; the second read will complete near-instantaneous because the num2 channel already has a number.

If you want to know more about channels in Go, I'd suggest to have a look at http://godoc.org/github.com/thomas11/csp -- this is a collection of Hoare's CSP examples written in Go.

答案3

得分: 4

回答问题“同时从多个通道读取”

有一种方法可以同时监听多个通道:

func main() {

    c1 := make(chan string)
    c2 := make(chan string)

    ...
    go func() {
        for {
            select {
                case msg1 := <- c1:
                fmt.Println(msg1)
                
                case msg2 := <- c2:
                fmt.Println(msg2)
             }
        }
    }()

在这个例子中,我创建了两个通道msg1和msg2。
然后我创建了一个带有无限循环的go例程。在这个循环中,我同时监听msg1和msg2。
这个系统允许您同时读取多个通道,并在消息到达时处理这些消息。

为了避免泄漏,我可能应该添加另一个通道来停止goroutine。

英文:

To answer the question "Reading from multiple channels simultaneously"

There is a way to listen to multiple channels simultaneously :

func main() {

    c1 := make(chan string)
    c2 := make(chan string)

    ...
    go func() {
        for {
            select {
                case msg1 := &lt;- c1:
                fmt.Println(msg1)
                
                case msg2 := &lt;- c2:
                fmt.Println(msg2)
             }
        }
    }()

In this example, I create a channel msg1 and msg2.
Then I create a go routine with an infinite loop. In this loop, I listen to msg1 AND msg2.
This system allow you to read to multiple channels simultaneously and to process the messages when the arrive.

In order to avoid leaks, I should probably add another channel to stop the goroutine.

huangapple
  • 本文由 发表于 2013年12月15日 17:33:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/20593126.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定