WaitGroup in Go
In this tutorial, we are going to discuss about WaitGroup in Go language.
Before discuss about WaitGroup, we will see a common problem with the Goroutines and try to solve it. Letβs see a simple code snippet illustrating this problem,
package main
import "fmt"
func runner1() {
fmt.Println("I am first runner")
}
func runner2() {
fmt.Println("I am second runner")
}
func execute() {
go runner1()
go runner2()
}
func main() {
// Launching both the runners
execute()
}
As you just saw there was nothing in the output, this because as soon as you launch both the Goroutines, your main function just got terminated.
So every program in Golang executes until main function is not terminated. So, what can we do with this problem?
Solution 1
We can wait for some time after launching the runners, for this purpose we will use βtimeβ packages function βSleepβ which pauses the execution of function for given duration,
package main
import "fmt"
import "time"
func runner1() {
fmt.Println("I am first runner")
}
func runner2() {
fmt.Println("I am second runner")
}
func execute() {
go runner1()
go runner2()
}
func main() {
// Launching both the runners
execute()
time.Sleep(time.Second)
}
Output
I am first runner
I am second runner
We just solve the problem, after launching our runners we wait for a second, so our main function was sleeping(blocked) for 1 sec. In that duration all of the go routines were executed successfully.
But Go language is a fast language, It doesnβt take 1 sec to just print 2 strings.
The problem is that, our executors executes in bit amount of time so we unnecessarily blocking the program for 1 sec.
In this example it doesnβt seems to be a critical problem but if you making a production grade server who is going to serve 1000βs of request concurrently this will be a big problem.
Solution 2
Letβs use another Golangβs standard library primitive βsync.WaitGroupβ. WaitGroup is actually a type of counter which blocks the execution of function (or might say A goroutine) until its internal counter become 0.
A WaitGroup is used to wait for a collection of Goroutines to finish executing. The control is blocked until all Goroutines finish executing.
Lets say we have 3 concurrently executing Goroutines spawned from the main
Goroutine. The main
Goroutines needs to wait for the 3 other Goroutines to finish before terminating. This can be accomplished using WaitGroup.
How It Works ?
WaitGroup exports 3 methods.

Note
WaitGroup is concurrency safe, so its safe to pass pointer to it as argument for Groutines.
Lets stop the theory and write some code right away π
package main
import (
"fmt"
"sync"
)
func runner1(wg *sync.WaitGroup) {
defer wg.Done() // This decreases counter by 1
fmt.Println("I am first runner")
}
func runner2(wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("I am second runner")
}
func execute() {
wg := new(sync.WaitGroup)
wg.Add(2)
// We are increasing the counter by 2 because we have 2 goroutines
go runner1(wg)
go runner2(wg)
// This Blocks the execution until its counter become 0
wg.Wait()
}
func main() {
// Launching both the runners
execute()
}
Output
I am first runner
I am second runner