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

我做了一个简单的代码示例来了解管道的用法,就在这里。


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)

}

现在,问题是我没有得到一致的输出(我知道这是一些并发问题,我还没有完全理解)。

输出

> 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

另一个人更改了代码(它正在运行)并放在func2循环之外,但我func2希望func1.


问题

所以,我想了解应该在哪里使用WaitGroup和?close(ch)


谢谢。

Temporarya

(一个 golang noobie)


小唯快跑啊
浏览 116回答 2
2回答

吃鸡游戏

您的代码中存在多个问题。在循环中,您正在生成多个 (3) goroutines 运行func2,并且在中func2,您将数据发送到ch2并调用close(ch2)。这是个问题。ch2当一个 goroutine 将数据发送到时,另一个goroutine 可能会关闭该通道,这会导致:panic: close of closed channelgoroutine 6 [running]:main.func2(0xc00006c000, 0xc000056180)    /home/projects/go-tuts/pipeline-loop.go:36 +0x72created by main.main    /home/projects/go-tuts/pipeline-loop.go:16 +0x10fexit status 2通常,您不需要多次关闭通道 - 您只需要在它们全部完成后关闭它们。WaitGroup为此你需要另一个;您需要将两个函数都传递给 a WaitGroup。更新:我个人使用一种“工作”模式,将数据生成到同一通道,并且在完成所有工作后需要关闭该通道:for something {    wg.Add(1)    go func(i int) {        work(ch)        wg.Done()    }}go func() {    wg.Wait()    close()}()我认为保持 API 清洁是一个好主意,WorkGroup因为WorkGroup它是关于如何同步工作而不是如何完成工作的。我已将您的代码更改为这种模式:https ://play.golang.org/p/vdCNsxWhgyQ

肥皂起泡泡

我怀疑您只希望一个通道从 ch1 读取并写入 ch2。创建 3 个 go-routines 来做同样的事情没有多大意义(而且你最终也会关闭相同的通道 multiple time 这会导致恐慌,正如 leaf bebop 指出的那样)func main() {&nbsp; &nbsp; ch1 := make(chan int, 10) // Use buffered channel so as to avoid clogging&nbsp; &nbsp; ch2 := make(chan string, 10)&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; for i := 0; i < 3; i++ {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; go func1(i, ch1, &wg)&nbsp; &nbsp; }&nbsp; &nbsp; go func2(ch1, ch2)&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; close(ch1)&nbsp; &nbsp; for val := range ch2 {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(val)&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP