Handle goroutines with sync.Waitgroup

Handle goroutines with sync.Waitgroup

Simple example on how to handle concurency with sync.WaitGroup.

If you are gonna do alot of requests at the same time, it could be a good idea to put them in goroutines to be more efficient. I want to show you how you can handle this in a easy way using sync.WaitGroup.

First we create a WaitGroup variable which we will use to control our goroutines, and a struct that will contain the response from the dog api we are gonna use in this example.

var wg sync.WaitGroup

var img struct {
	Status  string
	Message string
}

Then we create a easy get request function to test our code:

func randomDogImage(i *img, wg *sync.WaitGroup) {
	defer wg.Done() // notice this

	resp, err := http.Get("https://dog.ceo/api/breeds/image/random")
	if err != nil {
		fmt.Errorf("Failed http get request: %v", err)
		return
	}

	defer resp.Body.Close()

	err = json.NewDecoder(resp.Body).Decode(i)
	if err != nil {
		fmt.Errorf("Could not decode json: %v", err)
		return
	}
}

Notice the defer wg.Done().

This will tell the WaitGroup that this goroutine is “done”. Without calling this function the program will end up in a deadlock, since the WaitGroup will be forever waiting for the wg.Done() being called.

Then we can continue like this:

var i1, i2, i3, i4 img

wg.Add(1)
go randomDogImage(&i1, &wg)

wg.Add(1)
go randomDogImage(&i2, &wg)

wg.Add(1)
go randomDogImage(&i3, &wg)

wg.Add(1)
go randomDogImage(&i4, &wg)

wg.Wait()

// This will print when all requests are done
fmt.Println(i1.Message)
fmt.Println(i2.Message)
fmt.Println(i3.Message)
fmt.Println(i4.Message)

wg.Wait() will wait until all your goroutines are done before continuing.

Thanks for reading.