doushan2811 2019-02-11 05:30
浏览 70
已采纳

我应该在哪个函数中传递WaitGroup?

I have made a simple code example to understand the usage of pipeline, here it is.

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    ch1 := make(chan int, 10) // Use buffered channel so as to avoid clogging
    ch2 := make(chan string, 10)
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go func1(i, ch1, &wg)
        go func2(ch1, ch2)
    }
    wg.Wait()
    close(ch1)
    for val := range ch2 {
        fmt.Println(val)
    }
}

func func1(seconds int, ch chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    time.Sleep(time.Duration(seconds) * time.Second)
    fmt.Println(seconds)
    ch <- seconds
}

func func2(ch1 chan int, ch2 chan string) {
    for range ch1 {
        ch2 <- "hello"
    }
    close(ch2)
}

Now, the problem is I don't get consistent output ( I understand it's some concurrency issue, which I haven't fully understood ).

Output

> go run pipeline-loop.go 
0
1
2
hello
hello

> go run pipeline-loop.go 
0
1
2
hello
hello
hello

> go run pipeline-loop.go 
0
1
2
hello
hello

> go run pipeline-loop.go 
0
1
2
hello
hello

> go run pipeline-loop.go 
0
1
2
hello
hello
panic: close of closed channel

goroutine 6 [running]:
main.func2(0xc00006c000, 0xc000056180)
    /home/projects/go-tuts/pipeline-loop.go:36 +0x72
created by main.main
    /home/projects/go-tuts/pipeline-loop.go:16 +0x10f
exit status 2

Another guy changed the code ( and it was working ) and put func2 outside the loop but I want func2 for each iteration of the func1.

Problem

So, I want to understand as to where should the WaitGroup and close(ch) be used ?

Thanks.
Temporarya
( A golang noobie )

Update

Based on a user's answer, I changed the code, now I get output as expected ( but not the solution to this question ) but still there's a deadlock. https://play.golang.org/p/O_rp_FLvNh8

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    ch1 := make(chan int, 10) // Use buffered channel so as to avoid clogging
    ch2 := make(chan string, 10)
    var wg1 sync.WaitGroup
    // var wg2 sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg1.Add(1)
        go func1(i, ch1)
        go func2(ch1, ch2, &wg1)
    }
    for val := range ch2 {
        fmt.Println(val)
    }
    wg1.Wait()
    close(ch1)
    close(ch2)
}

// func func1(seconds int, ch chan<- int, wg *sync.WaitGroup) {
func func1(seconds int, ch chan<- int) {
    // defer wg.Done()
    time.Sleep(time.Duration(seconds) * time.Second)
    fmt.Println(seconds)
    ch <- seconds
}

func func2(ch1 chan int, ch2 chan string, wg *sync.WaitGroup) {
    defer wg.Done()
    for range ch1 {
        ch2 <- "hello"
    }
}
  • 写回答

2条回答 默认 最新

  • doudu6100 2019-02-11 05:44
    关注

    There are multiple problems in your code.

    In the loop, you are spawning multiple (3) goroutines that runs func2, and in func2, you send data to ch2 and call close(ch2). This is a problem. It can happen that when one goroutine is seding data to ch2, the other has closed that channel, which causes:

    panic: close of closed channel
    
    goroutine 6 [running]:
    main.func2(0xc00006c000, 0xc000056180)
        /home/projects/go-tuts/pipeline-loop.go:36 +0x72
    created by main.main
        /home/projects/go-tuts/pipeline-loop.go:16 +0x10f
    exit status 2
    

    In general, you don't need close a chanel multiple times - you only need to shut them once they are all finished. You need another WaitGroup for this; you need to pass both functions a WaitGroup.

    Further reading: https://blog.golang.org/pipelines

    UPDATE:

    Personally I use a pattern for "works" that produce data into a same channel and the channel needs to be closed after all works are done:

    for something {
        wg.Add(1)
        go func(i int) {
            work(ch)
            wg.Done()
        }
    }
    
    go func() {
        wg.Wait()
        close()
    }()
    

    I think it is a good idea that keeps the API clean from WorkGroup as WorkGroup is about how you sync the work instead of how the work is done.

    I have changed your code into this pattern: https://play.golang.org/p/vdCNsxWhgyQ

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

报告相同问题?

悬赏问题

  • ¥15 微信小程序协议怎么写
  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看