To wait for multiple goroutines to finish, we can use a wait group. |
|
![]() ![]() package main |
|
import ( "fmt" "sync" "time" ) |
|
This is the function we’ll run in every goroutine. |
func worker(id int) { fmt.Printf("Worker %d starting\n", id) |
Sleep to simulate an expensive task. |
time.Sleep(time.Second) fmt.Printf("Worker %d done\n", id) } |
func main() { |
|
This WaitGroup is used to wait for all the goroutines launched here to finish. Note: if a WaitGroup is explicitly passed into functions, it should be done by pointer. |
var wg sync.WaitGroup |
Launch several goroutines and increment the WaitGroup counter for each. |
for i := 1; i <= 5; i++ { wg.Add(1) |
Avoid re-use of the same |
i := i |
Wrap the worker call in a closure that makes sure to tell the WaitGroup that this worker is done. This way the worker itself does not have to be aware of the concurrency primitives involved in its execution. |
go func() { defer wg.Done() worker(i) }() } |
Block until the WaitGroup counter goes back to 0; all the workers notified they’re done. |
wg.Wait() |
Note that this approach has no straightforward way to propagate errors from workers. For more advanced use cases, consider using the errgroup package. |
}
|
$ go run waitgroups.go Worker 5 starting Worker 3 starting Worker 4 starting Worker 1 starting Worker 2 starting Worker 4 done Worker 1 done Worker 2 done Worker 5 done Worker 3 done |
|
The order of workers starting up and finishing is likely to be different for each invocation. |
Next example: Rate Limiting.