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

时间:2019-02-11 05:30:37

标签: go

我已经制作了一个简单的代码示例来了解管道的用法。

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的每次迭代。

问题

因此,我想了解应在何处使用WaitGroupclose(ch)

谢谢。
Temporarya
(golang noobie)

更新

根据用户的回答,我更改了代码,现在我得到了预期的输出(但不是此问题的解决方案),但是仍然存在死锁。 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 个答案:

答案 0 :(得分:1)

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

在循环中,您生成了运行Step3_BP2: delta_w_h1 = (X_train)^T * Err_h1的多(3)个goroutine,并在delta_b_h1 = sum(Err_h1)中将数据发送到django-djoser并调用func2。这是个问题。可能发生的情况是,当一个goroutine将数据sed到func2时,另一个已关闭该通道,从而导致:

ch2

通常,您不需要多次关闭香奈儿-您只需在它们全部完成后就关闭它们。为此,您需要另一个close(ch2);您需要将两个功能都传递给ch2

进一步阅读:https://blog.golang.org/pipelines

更新:

我个人使用“作品”模式将数据生成到同一通道,完成所有工作后需要关闭该通道:

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

我认为保持API清洁WaitGroup是个好主意,因为WaitGroup是关于如何同步工作而不是如何完成工作的。

我已将您的代码更改为以下模式:https://play.golang.org/p/vdCNsxWhgyQ

答案 1 :(得分:1)

我怀疑您只希望一个通道从ch1读取并写入ch2。创建3个go例程来执行相同的操作没有什么意义(而且您最终还会关闭相同的通道多重时间,这会引起叶子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)
    }
}