将sync.WaitGroup与外部函数一起使用的最佳方法

Sah*_*and 8 synchronization go

我有以下代码的一些问题:

package main

import (
"fmt"
"sync"
)
// This program should go to 11, but sometimes it only prints 1 to 10.
func main() {
    ch := make(chan int)
    var wg sync.WaitGroup
    wg.Add(2)
    go Print(ch, wg) //
    go func(){

        for i := 1; i <= 11; i++ {
            ch <- i
        }

        close(ch) 
        defer wg.Done()


    }()

    wg.Wait() //deadlock here
}

// Print prints all numbers sent on the channel.
// The function returns when the channel is closed.
func Print(ch <-chan int, wg sync.WaitGroup) {
    for n := range ch { // reads from channel until it's closed
        fmt.Println(n)
    }
    defer wg.Done()
}
Run Code Online (Sandbox Code Playgroud)

我在指定的地方陷入僵局.我尝试过设置wg.Add(1)而不是2,它解决了我的问题.我的信念是,我没有成功发送频道作为Printer函数的参数.有没有办法做到这一点?否则,我的问题的解决方案是用以下代码替换该go Print(ch, wg)行:

go func() {
Print(ch)
defer wg.Done()
}
Run Code Online (Sandbox Code Playgroud)

并将Printer功能更改为:

func Print(ch <-chan int) {
    for n := range ch { // reads from channel until it's closed
        fmt.Println(n)
    }

}
Run Code Online (Sandbox Code Playgroud)

什么是最好的解决方案?

Elw*_*nar 21

好吧,首先你的实际错误是你给Print方法一个副本sync.WaitGroup,所以它不会调用Done()你正在使用的方法Wait().

试试这个:

package main

import (
    "fmt"
    "sync"
)

func main() {    
    ch := make(chan int)

    var wg sync.WaitGroup
    wg.Add(2)    

    go Print(ch, &wg)

    go func() {  
        for i := 1; i <= 11; i++ {
            ch <- i
        }
        close(ch)
        defer wg.Done()
    }()          

    wg.Wait() //deadlock here
}                

func Print(ch <-chan int, wg *sync.WaitGroup) {
    for n := range ch { // reads from channel until it's closed
        fmt.Println(n)
    }            
    defer wg.Done()
}
Run Code Online (Sandbox Code Playgroud)

现在,更改您的Print方法以删除WaitGroup它是一个通常好主意:该方法不需要知道某些东西正在等待它完成它的工作.

  • 不要认为你可以删除print的waitgroup作为main的wg.Wait可能会在打印最后一个值之前失败,如果你只是等待发送者完成.此外,没有理由以延迟wg.Done()结束函数,延迟基本上意味着,最后运行它.放弃推迟 (2认同)