WaitGroups are a powerful synchronization primitive in Go, used to coordinate multiple goroutines. They allow you to wait for a collection of goroutines to finish executing before moving on to the next part of your program.
A WaitGroup is a struct from the sync
package. It maintains a counter of active goroutines and provides methods to increment, decrement, and wait for the counter to reach zero.
Add(delta int)
: Increments the counter by the specified deltaDone()
: Decrements the counter by 1Wait()
: Blocks until the counter becomes zeroHere's a simple example demonstrating how to use WaitGroups:
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
fmt.Println("All workers completed")
}
In this example, we create five worker goroutines and use a WaitGroup to ensure they all complete before the main function exits.
wg.Add()
before starting a new goroutinedefer wg.Done()
at the beginning of goroutine functions to ensure it's called even if the function panicsDone()
calls matches the number of Add()
callsWhile both WaitGroups and channels can be used for synchronization, they serve different purposes:
WaitGroups | Channels |
---|---|
Simple synchronization | Communication and synchronization |
Wait for multiple goroutines | Pass data between goroutines |
No data passing | Can be used for signaling completion |
Here's a more complex example using WaitGroups for parallel processing:
package main
import (
"fmt"
"sync"
"time"
)
func processItem(item int, results chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
time.Sleep(time.Duration(item) * time.Millisecond)
results <- item * 2
}
func main() {
items := []int{2, 4, 6, 8, 10}
results := make(chan int, len(items))
var wg sync.WaitGroup
for _, item := range items {
wg.Add(1)
go processItem(item, results, &wg)
}
go func() {
wg.Wait()
close(results)
}()
for result := range results {
fmt.Printf("Received result: %d\n", result)
}
}
This example demonstrates how to combine WaitGroups with channels for parallel processing and result collection.
WaitGroups are an essential tool for managing concurrent operations in Go. They provide a simple and effective way to synchronize multiple goroutines, ensuring that all tasks complete before moving on. By mastering WaitGroups, you'll be better equipped to handle complex concurrent scenarios in your Go programs.