WaitGroup in Go

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() 
}

Run in playground

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

Run in playground

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

Run in playground

WaitGroup in Go


Scroll to top