英文:
How to receive data from multiple channels using for/select syntax?
问题
我有一个案例,需要在多个通道上接收数据,并且以某种方式退出无限的for
循环。
这是一个简单的例子:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
sumChannel := make(chan int)
productChannel := make(chan int)
for i := 1; i <= 5; i++ {
wg.Add(1)
go compute(i, sumChannel, productChannel, &wg)
}
go func() {
wg.Wait()
close(sumChannel)
close(productChannel)
}()
for {
select {
case <-sumChannel:
fmt.Println("sum")
case <-productChannel:
fmt.Println("prod")
}
}
}
func compute(i int, sumChannel chan int, productChannel chan int, wg *sync.WaitGroup) {
time.Sleep(2 * time.Second)
sumChannel <- i + i
productChannel <- i * i
wg.Done()
}
问题是我得到了一个无限的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:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
sumChannel := make(chan int)
productChannel := make(chan int)
for i := 1; i <= 5; i++ {
wg.Add(1)
go compute(i, sumChannel, productChannel, &wg)
}
go func() {
wg.Wait()
close(sumChannel)
close(productChannel)
}()
for {
select {
case <-sumChannel:
fmt.Println("sum")
case <-productChannel:
fmt.Println("prod")
}
}
}
func compute(i int, sumChannel chan int, productChannel chan int, wg *sync.WaitGroup) {
time.Sleep(2 * time.Second)
sumChannel <- i + i
productChannel <- i * i
wg.Done()
}
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完成,你可以从那里取消循环:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
sumChannel := make(chan int)
productChannel := make(chan int)
closeChannel := make(chan bool)
for i := 1; i <= 5; i++ {
wg.Add(1)
go compute(i, sumChannel, productChannel, &wg)
}
go func() {
loop:
for {
select {
case <-sumChannel:
fmt.Println("sum")
case <-productChannel:
fmt.Println("prod")
case <-closeChannel:
fmt.Println("break")
break loop
}
}
}()
wg.Wait()
closeChannel <- true
fmt.Println("done")
}
func compute(i int, sumChannel chan int, productChannel chan int, wg *sync.WaitGroup) {
time.Sleep(2 * time.Second)
sumChannel <- i + i
productChannel <- i * i
wg.Done()
}
英文:
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:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
sumChannel := make(chan int)
productChannel := make(chan int)
closeChannel := make(chan bool)
for i := 1; i <= 5; i++ {
wg.Add(1)
go compute(i, sumChannel, productChannel, &wg)
}
go func() {
loop:
for {
select {
case <-sumChannel:
fmt.Println("sum")
case <-productChannel:
fmt.Println("prod")
case <-closeChannel:
fmt.Println("break")
break loop
}
}
}()
wg.Wait()
closeChannel <- true
fmt.Println("done")
}
func compute(i int, sumChannel chan int, productChannel chan int, wg *sync.WaitGroup) {
time.Sleep(2 * time.Second)
sumChannel <- i + i
productChannel <- i * i
wg.Done()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论