为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
小唯快跑啊 2023-06-05 18:02:16
我做了一个简单的代码示例来了解管道的用法,就在这里。package mainimport (    "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 012hellohello> go run pipeline-loop.go 012hellohellohello> go run pipeline-loop.go 012hellohello> go run pipeline-loop.go 012hellohello> go run pipeline-loop.go 012hellohellopanic: 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另一个人更改了代码(它正在运行)并放在func2循环之外,但我func2希望func1.问题所以,我想了解应该在哪里使用WaitGroup和?close(ch)谢谢。Temporarya(一个 golang noobie)
查看完整描述

2 回答

?
吃鸡游戏

TA贡献1829条经验 获得超7个赞

您的代码中存在多个问题。

在循环中,您正在生成多个 (3) goroutines 运行func2,并且在中func2,您将数据发送到ch2并调用close(ch2)。这是个问题。ch2当一个 goroutine 将数据发送到时,另一个goroutine 可能会关闭该通道,这会导致:

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

通常,您不需要多次关闭通道 - 您只需要在它们全部完成后关闭它们。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


查看完整回答
反对 回复 2023-06-05
?
肥皂起泡泡

TA贡献1829条经验 获得超6个赞

我怀疑您只希望一个通道从 ch1 读取并写入 ch2。创建 3 个 go-routines 来做同样的事情没有多大意义(而且你最终也会关闭相同的通道 multiple time 这会导致恐慌,正如 leaf bebop 指出的那样)


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)

    }

}


查看完整回答
反对 回复 2023-06-05
  • 2 回答
  • 0 关注
  • 146 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信