How to Use Sync.WaitGroup to Wait Goroutines in Go?
If you have many goroutines and your main goroutine finishes before the others, how do you wait for the other goroutines to finish?

WaitGroup is a counter. If there is a running goroutine, the counter increases one. If there is a goroutine done, the counter decreases one. Until the counter reset to zero, the goroutine is blocked by using the Wait()
method of WaitGroup. That is, as long as the counter is non-zero, the goroutine is blocked.
var wg sync.WaitGroup
: declare new WaitGroupwg.Add()
: increase counter when there are new goroutinewg.Done()
: decrease counter after the goroutine is donewg.Wait()
: block this goroutine until the counter reset to zero.
Let’s see the example code below:
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(j int) {
defer wg.Done()
time.Sleep(time.Duration(rand.Int63n(1000)) * time.Millisecond)
fmt.Println("Routine", j, "is done.")
}(i)
}
fmt.Println("Main routine is blocked")
wg.Wait()
fmt.Println("Main routine is done")
}
Main routine is blocked
Routine 3 is done.
Routine 7 is done.
Routine 8 is done.
Routine 5 is done.
Routine 0 is done.
Routine 9 is done.
Routine 2 is done.
Routine 6 is done.
Routine 1 is done.
Routine 4 is done.
Main routine is done
- You can pass value to routines by using the arguments of the function.
- You can use
defer
defers the execution of a function until the surrounding function returns. i.e., execute code after the function is done. - You can try to omit
wg.Wait()
and see what will happen?
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
go func(j int) {
wg.Add(1)
defer wg.Done()
time.Sleep(time.Duration(rand.Int63n(1000)) * time.Millisecond)
fmt.Println("Routine", j, "is done.")
}(i)
}
fmt.Println("Main routine is blocked")
// wg.Wait()
fmt.Println("Main routine is done")
}
Main routine is blocked
Main routine is done