Getting “fatal error: all goroutines are asleep - deadlock!” when using sync.WaitGroup

后端 未结 2 1764
太阳男子
太阳男子 2021-01-05 14:46

I\'m trying to spin off a set of goroutines, and then wait for them all to finish.

import \"sync\"

func doWork(wg sync.WaitGroup) error {
    defer wg.Done(         


        
相关标签:
2条回答
  • 2021-01-05 15:07

    As @Kevin mentioned, you will need to pass a reference to your WaitGroup. This is actually the one thing I do not like about WaitGroup because you would be mixing your concurrency logic with your business logic.

    So I came up with this generic function to solve this problem for me:

    // Parallelize parallelizes the function calls
    func Parallelize(functions ...func()) {
        var waitGroup sync.WaitGroup
        waitGroup.Add(len(functions))
    
        defer waitGroup.Wait()
    
        for _, function := range functions {
            go func(copy func()) {
                defer waitGroup.Done()
                copy()
            }(function)
        }
    }
    

    Here is an example:

    func1 := func() {
            for char := 'a'; char < 'a' + 3; char++ {
                fmt.Printf("%c ", char)
            }
    }
    
    func2 := func() {
            for number := 1; number < 4; number++ {
                fmt.Printf("%d ", number)
            }
    }
    
    Parallelize(func1, func2)  // a 1 b 2 c 3
    

    If you would like to use it, you can find it here https://github.com/shomali11/util

    0 讨论(0)
  • 2021-01-05 15:13

    You need to pass a pointer to the WaitGroup, and not the WaitGroup object. When you pass the actual WaitGroup, Go makes a copy of the value, and calls Done() on the copy. The result is the original WaitGroup will have ten Add's and no Done's, and each copy of the WaitGroup will have one Done() and however many Add's were there when the WaitGroup was passed to the function.

    Pass a pointer instead, and every function will reference the same WaitGroup.

    import "sync"
    
    func doWork(wg *sync.WaitGroup) error {
        defer wg.Done()
        // Do some heavy lifting... request URL's or similar
        return nil
    }
    
    func main() {
        wg := &sync.WaitGroup{}
        for i := 0; i < 10; i++ {
            wg.Add(1)
            go doWork(wg)
        }
    }
    
    0 讨论(0)
提交回复
热议问题