如何在Go中将通道中的值收集到切片中?

假设我有一个帮助器函数,它返回一段可变长度的整数。我想并行运行各种值,并将输出收集在一个大切片中。我的第一次尝试如下: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 但无法找到与我的用例非常匹配的内容。有什么想法吗?


凤凰求蛊
浏览 66回答 1
1回答

慕尼黑8549860

在此版本的代码中,执行将被阻止,直到关闭。chch始终在负责推送到 的例程结束时关闭。由于程序在例程中推送到,因此不需要使用缓冲通道。chchpackage mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "golang.org/x/sync/errgroup")func main() {&nbsp; &nbsp; ch := make(chan int)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; g := new(errgroup.Group)&nbsp; &nbsp; &nbsp; &nbsp; for n := 2; n <= 3; n++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; n := n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; g.Go(func() error {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for _, i := range helper(n) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ch <- i&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if err := g.Wait(); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; panic(err)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; close(ch)&nbsp; &nbsp; }()&nbsp; &nbsp; out := make([]int, 0)&nbsp; &nbsp; for i := range ch {&nbsp; &nbsp; &nbsp; &nbsp; out = append(out, i)&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println(out) // should have the same elements as [0 1 0 1 2]}func helper(n int) []int {&nbsp; &nbsp; out := make([]int, 0)&nbsp; &nbsp; for i := 0; i < n; i++ {&nbsp; &nbsp; &nbsp; &nbsp; out = append(out, i)&nbsp; &nbsp; }&nbsp; &nbsp; return out}这是第一个代码的固定版本,它很复杂,但演示了 的用法。sync.WaitGrouppackage mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "sync"&nbsp; &nbsp; "golang.org/x/sync/errgroup")func main() {&nbsp; &nbsp; out := make([]int, 0)&nbsp; &nbsp; ch := make(chan int)&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; for i := range ch {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out = append(out, i)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }()&nbsp; &nbsp; g := new(errgroup.Group)&nbsp; &nbsp; for n := 2; n <= 3; n++ {&nbsp; &nbsp; &nbsp; &nbsp; n := n&nbsp; &nbsp; &nbsp; &nbsp; g.Go(func() error {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for _, i := range helper(n) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ch <- i&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; }&nbsp; &nbsp; if err := g.Wait(); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; panic(err)&nbsp; &nbsp; }&nbsp; &nbsp; close(ch)&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; // time.Sleep(time.Second)&nbsp; &nbsp; fmt.Println(out) // should have the same elements as [0 1 0 1 2]}func helper(n int) []int {&nbsp; &nbsp; out := make([]int, 0)&nbsp; &nbsp; for i := 0; i < n; i++ {&nbsp; &nbsp; &nbsp; &nbsp; out = append(out, i)&nbsp; &nbsp; }&nbsp; &nbsp; return out}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java