WaitGroup

Advanced Concurrency

WaitGroup

🙋 Need help? Ask an expert now!

Wait for Goroutines to Return

In Go, we use the sync.WaitGroup structure in order to wait for a group of goroutines to finish their task prior to doing something else -- like maybe sending an email with a summary report to a user.

In Practice

package main
            
            import (
                "fmt"
                "sync"
            )
            
            func main() {
                // Create a new WaitGroup
                var wg sync.WaitGroup
                // Let's pretend we're doing something useful here -- like iterating over a slice of datasets
                for i := 1; i < 11; i++ {
                    // In this example, we increment one-by-one, however, you can also increment once by the total, e.g., `wg.Add(10)` in this case
                    // NB: remember that the `wg.Add` call must occur before the corresponding `wg.Done`, because if `wg.Done` count exceeds the number added,
                    //     we will encounter a panic in the goroutine that calls `wg.Done`
                    wg.Add(1)
                    go addNumber(i, i*10+i, &wg)
                }
            
                // This will block this goroutine until all other goroutines have called `wg.Done` and the count of 'outstanding' routines is therefore 0
                // NB: If you want to 'timeout' you can use Go's context timeout channel or even just the Timer chan factory in the "time" package
                wg.Wait()
                // Yay we finished!
                fmt.Println("All goroutines done, exiting...")
            }
            
            func addNumber(idx, n int, wg *sync.WaitGroup) {
                // Best practice is to defer this call, so that regardless what happens, even if there's a panic elsewhere in the goroutine,
                // the main goroutine will not be stuck forver (waiting on the wg.Wait() to return)
                defer wg.Done()
                // NB: In the event that you might want to be able to notify the main goroutine of an error, the idiomatic way to do that would be
                //     to pass errors into a `chan` that the main goroutine would check for errors after all of the goroutines have returned
                fmt.Println("In goroutine number", idx, "and we found that n*n =", n*n)
            }

In the event that you need to 'throttle' the waitgroups, or process data in chunks, the SizedWaitGroup section is a great reference!

Edit Me on GitHub!