通道提前终止

我正在为管道制作一系列 go 例程的原型,每个例程都执行一个转换。例程在所有数据通过之前终止。


我查了多纳万和克尼汉的书,并在谷歌上搜索了解决方案。


这是我的代码:


package main


import (

    "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 you

apricots are good for you

运行main的结果不一致。有时我同时得到两条线。有时我只得到苹果。有时什么也没有输出。


牛魔王的故事
浏览 103回答 2
2回答

四季花海

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

DIEA

您正在调用wg.Wait一个 goroutine,因此main可以在其他例程完成之前返回(因此您的程序退出)。这会导致您看到的行为,但仅从 Goroutine 中取出是不够的。您还滥用了WaitGroup一般性;你的Add和Done调用 彼此不相关,并且你没有那么多Dones&nbsp;Add,所以 sWaitGroup永远不会完成。如果您在循环中调用Add,则每次循环迭代也必须导致调用Done;正如您现在所拥有的,您defer wg.Done()在每个循环之前,然后Add在循环内部调用,从而产生一个Done和多个Adds。该代码需要进行重大修改才能按预期工作。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go