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

报告相同问题?

悬赏问题

  • ¥15 Pyqt 如何正确的关掉Qthread,并且释放其中的锁?
  • ¥30 网站服务器通过node.js部署了一个项目!前端访问失败
  • ¥15 WPS访问权限不足怎么解决
  • ¥15 java幂等控制问题
  • ¥15 海湾GST-DJ-N500
  • ¥15 氧化掩蔽层与注入条件关系
  • ¥15 Django DRF 如何反序列化得到Python对象类型数据
  • ¥15 多数据源与Hystrix的冲突
  • ¥15 如何在线硕士了解,广告太多,希望有真实接触过的人回答下?(标签-学习|关键词-在线硕士)
  • ¥15 zabbix6.4与frp如何进行联动