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

通道提前终止

通道提前终止

Go
牛魔王的故事 2023-07-17 13:57:25
我正在为管道制作一系列 go 例程的原型,每个例程都执行一个转换。例程在所有数据通过之前终止。我查了多纳万和克尼汉的书,并在谷歌上搜索了解决方案。这是我的代码:package mainimport (    "fmt"    "sync")func main() {    a1 := []string{"apple", "apricot"}    chan1 := make(chan string)    chan2 := make(chan string)    chan3 := make(chan string)    var wg sync.WaitGroup    go Pipe1(chan2, chan1, &wg)    go Pipe2(chan3, chan2, &wg)    go Pipe3(chan3, &wg)    func (data []string) {        defer wg.Done()        for _, s := range data {            wg.Add(1)            chan1 <- s        }        go func() {            wg.Wait()            close(chan1)        }()    }(a1)}func Pipe1(out chan<- string, in <-chan string, wg *sync.WaitGroup) {    defer wg.Done()    for s := range in {        wg.Add(1)        out <- s + "s are"    }}func Pipe2(out chan<- string, in <-chan string, wg *sync.WaitGroup) {    defer wg.Done()    for s := range in {        wg.Add(1)        out <- s + " good for you"    }}func Pipe3(in <-chan string, wg *sync.WaitGroup) {    defer wg.Done()    for s := range in {        wg.Add(1)        fmt.Println(s)    }}我的预期输出是:apples are good for youapricots are good for you运行main的结果不一致。有时我同时得到两条线。有时我只得到苹果。有时什么也没有输出。
查看完整描述

2 回答

?
四季花海

TA贡献1811条经验 获得超5个赞

您的 WaitGroup.Add 和 WaitGroup.Done 调用不匹配。然而,在这种情况下,“我完成了”信号通常是通过关闭输出通道来给出的。仅当工作在多个 goroutine 之间共享时才需要 WaitGroups(即多个 goroutine 消耗相同的通道),但这里的情况并非如此。


package main


import (

    "fmt"

)


func main() {

    a1 := []string{"apple", "apricot"}


    chan1 := make(chan string)

    chan2 := make(chan string)

    chan3 := make(chan string)


    go func() {

        for _, s := range a1 {

            chan1 <- s

        }


        close(chan1)

    }()


    go Pipe1(chan2, chan1)

    go Pipe2(chan3, chan2)


    // This range loop terminates when chan3 is closed, which Pipe2 does after

    // chan2 is closed, which Pipe1 does after chan1 is closed, which the

    // anonymous goroutine above does after it sent all values.

    for s := range chan3 {

        fmt.Println(s)

    }

}


func Pipe1(out chan<- string, in <-chan string) {

    for s := range in {

        out <- s + "s are"

    }


    close(out) // let caller know that we're done

}


func Pipe2(out chan<- string, in <-chan string) {

    for s := range in {

        out <- s + " good for you"

    }


    close(out) // let caller know that we're done

}

在操场上尝试一下:https ://play.golang.org/p/d2J4APjs_lL


查看完整回答
反对 回复 2023-07-17
?
DIEA

TA贡献1820条经验 获得超2个赞

您正在调用wg.Wait一个 goroutine,因此main可以在其他例程完成之前返回(因此您的程序退出)。这会导致您看到的行为,但仅从 Goroutine 中取出是不够的。

您还滥用了WaitGroup一般性;你的AddDone调用 彼此不相关,并且你没有那么多DoneAdd,所以 sWaitGroup永远不会完成。如果您在循环中调用Add,则每次循环迭代也必须导致调用Done;正如您现在所拥有的,您defer wg.Done()在每个循环之前,然后Add在循环内部调用,从而产生一个Done和多个Adds。该代码需要进行重大修改才能按预期工作。


查看完整回答
反对 回复 2023-07-17
  • 2 回答
  • 0 关注
  • 102 浏览
慕课专栏
更多

添加回答

举报

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