How to wait for all goroutines to finish in Golang
Go has a dedicated package sync that simplifies syncrhonization of goroutines. However in simple cases, goroutines can be synchronized with ordinary channels. In this post we will look at both methods on example.
Waiting for a single goroutine
Waiting for a single goroutine can be implemented with a help of a channel. When finished execution, worker goroutine sends a message to main goroutine awaiting for it. Like in the following example.
package main
import (
"fmt"
"time"
)
func worker(finished chan bool) {
fmt.Println("Worker: Started")
time.Sleep(time.Second)
fmt.Println("Worker: Finished")
finished <- true
}
func main() {
finished := make(chan bool)
fmt.Println("Main: Starting worker")
go worker(finished)
fmt.Println("Main: Waiting for worker to finish")
<- finished
fmt.Println("Main: Completed")
}
Running the code produces the following output:
Main: Starting worker
Main: Waiting for worker to finish
Worker: Started
Worker: Finished
Main: Completed
Waiting for multiple goroutines
If we need to wait for multiple goroutines to complete, sync.WaitGroup goes to the rescue. A WaitGroup allows to wait for a collection of goroutines to finish. The main goroutine calls Add to set the number of goroutines to wait for. Then each of the worker goroutines runs and calls Done when finished. At the same time, Wait can be used to block until all goroutines have finished. The following example illustrates it.
package main
import (
"fmt"
"sync"
"time"
)
func worker(wg *sync.WaitGroup, id int) {
defer wg.Done()
fmt.Printf("Worker %v: Started\n", id)
time.Sleep(time.Second)
fmt.Printf("Worker %v: Finished\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
fmt.Println("Main: Starting worker", i)
wg.Add(1)
go worker(&wg, i)
}
fmt.Println("Main: Waiting for workers to finish")
wg.Wait()
fmt.Println("Main: Completed")
}
Running the code produces the following output:
Main: Starting worker 0
Main: Starting worker 1
Main: Starting worker 2
Main: Starting worker 3
Main: Starting worker 4
Main: Waiting for workers to finish
Worker 4: Started
Worker 1: Started
Worker 2: Started
Worker 0: Started
Worker 3: Started
Worker 3: Finished
Worker 1: Finished
Worker 4: Finished
Worker 2: Finished
Worker 0: Finished
Main: Completed
Want to learn more?
Watch GopherCon 2014 A Channel Compendium by John Graham-Cumming. It has very interesting insights on how to use channels for synchronization in Go.