假设我有一个帮助器函数,它返回一段可变长度的整数。我想并行运行各种值,并将输出收集在一个大切片中。我的第一次尝试如下:helper(n int)helper(n)n
package main
import (
"fmt"
"golang.org/x/sync/errgroup"
)
func main() {
out := make([]int, 0)
ch := make(chan int)
go func() {
for i := range ch {
out = append(out, i)
}
}()
g := new(errgroup.Group)
for n := 2; n <= 3; n++ {
n := n
g.Go(func() error {
for _, i := range helper(n) {
ch <- i
}
return nil
})
}
if err := g.Wait(); err != nil {
panic(err)
}
close(ch)
// time.Sleep(time.Second)
fmt.Println(out) // should have the same elements as [0 1 0 1 2]
}
func helper(n int) []int {
out := make([]int, 0)
for i := 0; i < n; i++ {
out = append(out, i)
}
return out
}
但是,如果我运行此示例,我不会获得所有5个预期值,而是得到
[0 1 0 1]
(如果我取消注释,我确实得到了所有五个值,但这不是一个可接受的解决方案)。time.Sleep[0 1 2 0 1]
似乎问题在于正在 goroutine 中更新,但函数在完成更新之前返回。outmain
可行的一件事是使用大小为 5 的缓冲通道:
func main() {
ch := make(chan int, 5)
g := new(errgroup.Group)
for n := 2; n <= 3; n++ {
n := n
g.Go(func() error {
for _, i := range helper(n) {
ch <- i
}
return nil
})
}
if err := g.Wait(); err != nil {
panic(err)
}
close(ch)
out := make([]int, 0)
for i := range ch {
out = append(out, i)
}
fmt.Println(out) // should have the same elements as [0 1 0 1 2]
}
但是,尽管在这个简化的示例中我知道输出的大小应该是多少,但在我的实际应用中,这先验地不知道。从本质上讲,我想要的是一个“无限”的缓冲区,这样发送到通道永远不会阻塞,或者是一种更习惯的方式来实现同样的事情;我已经阅读了 https://blog.golang.org/pipelines 但无法找到与我的用例非常匹配的内容。有什么想法吗?
慕尼黑8549860
相关分类