The Golang errgroup package is used to provide tools for synchronization, error propagation and context cancellation for a group of goroutines that perform a common task.
Let us take a look at a how to use the errgroup package.
Import Required Package
To use the errgroup package, you need to import it using the import clause. The example code below shows how to import the errgroup package.
WithContext Function
The errgroup package provides us with the WithContext function. The function returns a new group, and the associated context.
If the function passed returns a non0-nil error or the wait returns, the context is cancelled.
Go Func
The second function provided by the errgroup package is the Go function. This function calls a specified function to a new goroutine.
If the first call returns non-nil error, this cancels the Context.
Wait Func
The third function is the Wait function. This function waits a block until the function calls from the Go method return a value.
Example
Let us see how we can use the errgroup package. Let us begin with a set of go routines that simply print a value.
import "fmt"
func main() {
for i := 0; i < 10; i++ {
go fmt.Println("Processing task: ", i)
}
}
Here, we have a for loop that simply runs a bunch of goroutines and print the current value in the loop iteration.
If we run the code above, you notice that it does not actually print anything. This is because the goroutines are inside the main function and once the main function ends, Go will terminate the entire program, whether or not the goroutines have finished.
We can solve this by using the sync package from the standard library. Check our tutorial on golang sync to learn more.
https://linuxhint.com/golang-sync/
We can redefine the code above using WaitGroups as shown below:
import (
"fmt"
"sync"
)
func main() {
wg := &sync.WaitGroup{}
for i := 0; i < 10; i++ {
wg.Add(1)
go func (task int) {
defer wg.Done()
fmt.Println("Processing task: ", task)
}(i)
}
wg.Wait()
}
Here, we introduce “concurrency” using WaitGroups. In a nutshell, the waitgroup is a counter that allows us to block the main function from exiting until all the goroutines have finished executing.
The waitgroup works by creating a counter that keeps tract of the number of goroutines in the que. Once a goroutine completes, we remove it from the que. Once the que is 0, the waitgroup unblocks the execution and returns to main.
Notice the Add function? We use this to add a value to the waitgroup que counter. Once the execution is done, we remove the completed goroutine using the Done method.
Using Errgroup
In the above example, we process a group of goroutines using the sync package in Go. However, there is no mechanism to handle any errors. Although not necessary for a simple example as one shown above, it is important to lots of applications.
For that, we can use the errgroup function which allows to handle errors in a wait group. Take a look at the example below:
import (
"fmt"
"log"
"math/rand"
"golang.org/x/sync/errgroup"
)
func Task(task int) error {
if rand.Intn(10) == task {
return fmt.Errorf("Task %v failed", task)
}
fmt.Printf("Task %v completed", task)
return nil
}
func main() {
eg := &errgroup.Group{}
for i := 0; i < 10; i++ {
task := i
eg.Go(func() error {
return Task(task)
})
}
if err := eg.Wait(); err != nil {
log.Fatal("Error", err)
}
fmt.Println("Completed successfully!")
}
In this example, we introduce a simple function that generates a random integer. If the random value is equal to the task, we return an error.
We then use the error group to handle the errors using the Group{} and Go functions.
Closing
This guide covered how to introduce and work with WaitGroups and handle errors using the errgroup package.