egreb.net

Handle goroutines with sync.Waitgroup

Handle goroutines with sync.Waitgroup

published 10 July 2018

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.