如何使用for/select语法从多个通道接收数据?

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

How to receive data from multiple channels using for/select syntax?

问题

我有一个案例,需要在多个通道上接收数据,并且以某种方式退出无限的for循环。

这是一个简单的例子:

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. )
  7. func main() {
  8. var wg sync.WaitGroup
  9. sumChannel := make(chan int)
  10. productChannel := make(chan int)
  11. for i := 1; i <= 5; i++ {
  12. wg.Add(1)
  13. go compute(i, sumChannel, productChannel, &wg)
  14. }
  15. go func() {
  16. wg.Wait()
  17. close(sumChannel)
  18. close(productChannel)
  19. }()
  20. for {
  21. select {
  22. case <-sumChannel:
  23. fmt.Println("sum")
  24. case <-productChannel:
  25. fmt.Println("prod")
  26. }
  27. }
  28. }
  29. func compute(i int, sumChannel chan int, productChannel chan int, wg *sync.WaitGroup) {
  30. time.Sleep(2 * time.Second)
  31. sumChannel <- i + i
  32. productChannel <- i * i
  33. wg.Done()
  34. }

问题是我得到了一个无限的for循环。我知道我应该创建一个新的通道(例如quit)来退出循环。但是,我真的不明白在哪里放置quit信号,因为我不知道确切的位置可以确保所有的goroutine都已经完成。

英文:

I have case where I need to receive data on multiple channels and somehow quit infinite for loop.

Here is simple example:

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;sync&quot;
  5. &quot;time&quot;
  6. )
  7. func main() {
  8. var wg sync.WaitGroup
  9. sumChannel := make(chan int)
  10. productChannel := make(chan int)
  11. for i := 1; i &lt;= 5; i++ {
  12. wg.Add(1)
  13. go compute(i, sumChannel, productChannel, &amp;wg)
  14. }
  15. go func() {
  16. wg.Wait()
  17. close(sumChannel)
  18. close(productChannel)
  19. }()
  20. for {
  21. select {
  22. case &lt;-sumChannel:
  23. fmt.Println(&quot;sum&quot;)
  24. case &lt;-productChannel:
  25. fmt.Println(&quot;prod&quot;)
  26. }
  27. }
  28. }
  29. func compute(i int, sumChannel chan int, productChannel chan int, wg *sync.WaitGroup) {
  30. time.Sleep(2 * time.Second)
  31. sumChannel &lt;- i + i
  32. productChannel &lt;- i * i
  33. wg.Done()
  34. }

The problem is I get infinite for loop. I know that I should create new channel (for instance,quit) for quitting from loop. But, I really don't understand where to put signal to quit, because I don't know exact place where I can be sure that all goroutines finished.

答案1

得分: 1

如果你在一个go routine中运行for循环,然后等待计算的go routines完成,你可以从那里取消循环:

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. )
  7. func main() {
  8. var wg sync.WaitGroup
  9. sumChannel := make(chan int)
  10. productChannel := make(chan int)
  11. closeChannel := make(chan bool)
  12. for i := 1; i <= 5; i++ {
  13. wg.Add(1)
  14. go compute(i, sumChannel, productChannel, &wg)
  15. }
  16. go func() {
  17. loop:
  18. for {
  19. select {
  20. case <-sumChannel:
  21. fmt.Println("sum")
  22. case <-productChannel:
  23. fmt.Println("prod")
  24. case <-closeChannel:
  25. fmt.Println("break")
  26. break loop
  27. }
  28. }
  29. }()
  30. wg.Wait()
  31. closeChannel <- true
  32. fmt.Println("done")
  33. }
  34. func compute(i int, sumChannel chan int, productChannel chan int, wg *sync.WaitGroup) {
  35. time.Sleep(2 * time.Second)
  36. sumChannel <- i + i
  37. productChannel <- i * i
  38. wg.Done()
  39. }

运行它

英文:

If you run the for loop in a go routine and then wait for the compute go routines to finish, you can cancel the loop from there:

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;sync&quot;
  5. &quot;time&quot;
  6. )
  7. func main() {
  8. var wg sync.WaitGroup
  9. sumChannel := make(chan int)
  10. productChannel := make(chan int)
  11. closeChannel := make(chan bool)
  12. for i := 1; i &lt;= 5; i++ {
  13. wg.Add(1)
  14. go compute(i, sumChannel, productChannel, &amp;wg)
  15. }
  16. go func() {
  17. loop:
  18. for {
  19. select {
  20. case &lt;-sumChannel:
  21. fmt.Println(&quot;sum&quot;)
  22. case &lt;-productChannel:
  23. fmt.Println(&quot;prod&quot;)
  24. case &lt;-closeChannel:
  25. fmt.Println(&quot;break&quot;)
  26. break loop
  27. }
  28. }
  29. }()
  30. wg.Wait()
  31. closeChannel &lt;- true
  32. fmt.Println(&quot;done&quot;)
  33. }
  34. func compute(i int, sumChannel chan int, productChannel chan int, wg *sync.WaitGroup) {
  35. time.Sleep(2 * time.Second)
  36. sumChannel &lt;- i + i
  37. productChannel &lt;- i * i
  38. wg.Done()
  39. }

Run it

huangapple
  • 本文由 发表于 2022年7月27日 18:13:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/73136112.html
匿名

发表评论

匿名网友

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

确定