dongzhuang1923 2019-08-21 15:04
浏览 39
已采纳

频道过早终止

I am prototyping a series of go routines for a pipeline that each perform a transformation. The routines are terminating before all the data has passed through.

I have checked Donavan and Kernighan book and Googled for solutions.

Here is my code:

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)
    }
}


My expected output is:

apples are good for you
apricots are good for you

The results of running main are inconsistent. Sometimes I get both lines. Sometimes I just get the apples. Sometimes nothing is output.

  • 写回答

2条回答 默认 最新

  • dousui4577 2019-08-21 15:56
    关注

    As Adrian already pointed out, your WaitGroup.Add and WaitGroup.Done calls are mismatched. However, in cases like this the "I am done" signal is typically given by closing the output channel. WaitGroups are only necessary if work is shared between several goroutines (i.e. several goroutines consume the same channel), which isn't the case here.

    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
    }
    

    Try it on the playground: https://play.golang.org/p/d2J4APjs_lL

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥20 软件测试决策法疑问求解答
  • ¥15 win11 23H2删除推荐的项目,支持注册表等
  • ¥15 matlab 用yalmip搭建模型,cplex求解,线性化处理的方法
  • ¥15 qt6.6.3 基于百度云的语音识别 不会改
  • ¥15 关于#目标检测#的问题:大概就是类似后台自动检测某下架商品的库存,在他监测到该商品上架并且可以购买的瞬间点击立即购买下单
  • ¥15 神经网络怎么把隐含层变量融合到损失函数中?
  • ¥15 lingo18勾选global solver求解使用的算法
  • ¥15 全部备份安卓app数据包括密码,可以复制到另一手机上运行
  • ¥20 测距传感器数据手册i2c
  • ¥15 RPA正常跑,cmd输入cookies跑不出来