Open In App

Using WaitGroup in Golang

Improve
Improve
Like Article
Like
Save
Share
Report

Go routines are a great selling point for golang, making it a choice of a lots of developers out there. In this post we will see a common problem with these goroutines and try to solve it.

Let’s see a simple code snippet illustrating this problem,

Go




package main
 
import "fmt"
 
func runner1() {
    fmt.Print("\nI am first runner")
}
 
func runner2() {
    fmt.Print("\nI 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. And every program in Golang executes until main function is not terminated. So, what can we do with this problem

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,

Go




package main
 
import (
    "fmt"
    "time"
)
 
func runner1() {
    fmt.Print("\nI am first runner")
}
 
func runner2() {
    fmt.Print("\nI am second runner")
}
 
func execute() {
    go runner1()
    go runner2()
 
}
 
func main() {
 
    // Launching both the runners
    execute()
    time.Sleep(time.Second)
}


 

Output:

I am second runner
I am first 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 Golang 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.

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.

How It Works ?

WaitGroup exports 3 methods.

1 Add(int)  It increases WaitGroup counter by given integer value.
2 Done()  It decreases WaitGroup counter by 1, we will use it to indicate termination of a goroutine.
3 Wait() It Blocks the execution until it’s internal counter becomes 0.

Note: WaitGroup is concurrency safe, so its safe to pass pointer to it as argument for Groutines.

Go




package main
 
import (
    "fmt"
    "sync"
)
 
func runner1(wg *sync.WaitGroup) {
    defer wg.Done() // This decreases counter by 1
    fmt.Print("\nI am first runner")
 
}
 
func runner2(wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Print("\nI 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 second runner
I am first runner

The output is same but we out program doesn’t block for 1 sec . Pattern, we showed you above is a common practice in writing concurrent code in Golang.



Last Updated : 01 Nov, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads