为了账号安全,请及时绑定邮箱和手机立即绑定

去例行程序神秘地结束,频道关闭而没有达到关闭语句

去例行程序神秘地结束,频道关闭而没有达到关闭语句

Go
繁花如伊 2022-09-19 14:50:58
我创建了以下简单程序来测试使用通道的扇入扇出模式。它的作用是生成一些 go 例程来计算来自输入通道的数字的平方,并将该平方发送到输出通道。然后,所有输出通道将合并到一个通道中,以在 中打印正方形。mainfunc calculateSquare(in <-chan int) <-chan int {    out := make(chan int)    go func() {       for num := range in {           fmt.Printf("Receving num %v\n", num)           out <- num * num           fmt.Printf("Sending square %v\n", num * num)       }       fmt.Println("Closing out")       close(out)    }()    return out}func fanOut(in <-chan int, workerCount int) []<-chan int {    outs := make([]<-chan int, 0, workerCount)    for i := 0 ; i < workerCount ; i++ {        outs = append(outs, calculateSquare(in))    }    return outs}func fanIn(outs []<-chan int) <-chan int {    var wg sync.WaitGroup    merge := make(chan int)    for _, out := range outs {        wg.Add(1)        go func() {            for result := range out {                merge <- result            }            wg.Done()        }()    }    go func() {        wg.Wait()        fmt.Println("Closing merge")        close(merge)    }()    return merge}func main() {    in := make(chan int)    go func() {        for i := 0 ; i < 4 ; i++ {            fmt.Printf("Sending num %v\n", i)            in <- i        }        close(in)    }()    outs := fanOut(in, 5)    merge := fanIn(outs)    for num := range merge {        fmt.Printf("Final square %v\n", num)    }}在函数中,我将4个数字0 -> 3发送到输入通道,我希望看到控制台中打印的4个正方形。但是,当我运行该程序时,即使输出有点波动,但我从未见过控制台中打印的4个平方数字。main下面是我看到的示例输出。Sending num 0Sending num 1Sending num 2Sending num 3Closing outReceving num 0Receving num 1Receving num 2Sending square  4Closing outReceving num 3Final square 4Closing merge如果有人能向我解释为什么被印刷但永远不会来,我将不胜感激。此外,如果没有打印,频道是如何关闭的。我只看到2 ,但是,我合并结果的等待组结束了它。Receving num 1Sending square 1Sending square 1outputClosing outWait()我一定是在某个地方做错了什么。
查看完整描述

2 回答

?
红颜莎娜

TA贡献1842条经验 获得超12个赞

要修复:

for _, out := range outs {
    wg.Add(1)

    out := out // <- add this

为什么?

https://golang.org/doc/effective_go 是一个很好的资源,涵盖了通道部分末尾的确切关闭错误(@JimB提到):

写起来可能看起来很奇怪

要求 := 要求

但它是合法的和惯用语在Go中这样做。您将获得具有相同名称的变量的新版本,故意在局部隐藏循环变量,但对于每个 goroutine 是唯一的。


查看完整回答
反对 回复 2022-09-19
?
慕无忌1623718

TA贡献1744条经验 获得超4个赞

您的问题在下面的代码中,for 函数中的循环。fanIn


    for _, out := range outs {

        wg.Add(1)


        go func() {

            for result := range out {

                merge <- result

            }


            wg.Done()

        }()

    }

这样做的原因是你在gofunc中使用迭代器变量,当gofunc要使用它时,循环就走到了它的尽头。out


这在子主题下的 go/wiki/常见错误中进行了描述Using goroutines on loop iterator variables


有关更多示例 - 请阅读此


校正后的循环应如下所示,


    for _, out := range outs {

        wg.Add(1)


        go func(c <- chan int) {

            for result := range c {

                merge <- result

            }


            wg.Done()

        }(out)

    }


查看完整回答
反对 回复 2022-09-19
  • 2 回答
  • 0 关注
  • 68 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信