Mastering Go Concurrency: When to Use WaitGroup vs Mutex
This article examines Go's sync package, detailing how WaitGroup coordinates the completion of multiple goroutines while Mutex protects shared resources, compares their purposes and use cases, and provides practical code examples to help developers choose the right tool for concurrent programming.
Introduction
In Go's concurrency model, correct synchronization of goroutines is essential. The sync package provides primitives such as WaitGroup and Mutex for coordinating execution and protecting shared state.
WaitGroup
Purpose
WaitGroupwaits for a set of goroutines to finish. The counter is increased with Add(delta int) before launching goroutines and decreased with Done() (equivalent to Add(-1)) when a goroutine completes. Wait() blocks until the counter reaches zero.
Typical usage
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1) // increment counter
go func(id int) {
defer wg.Done() // decrement when finished
// perform work for goroutine id
}(i)
}
wg.Wait() // blocks until all five goroutines call Done()Key points
The WaitGroup value must not be copied after first use; pass a pointer if needed.
Calling Add after Wait has started can cause a deadlock.
Typical scenario : coordinating a batch of independent tasks where the program must not proceed until all tasks have completed.
Mutex
Purpose
Mutexprovides mutual exclusion for a critical section, ensuring that only one goroutine accesses the protected data at a time.
Typical usage
var mu sync.Mutex
var counter int
for i := 0; i < 5; i++ {
go func() {
mu.Lock() // acquire exclusive access
counter++ // modify shared variable safely
mu.Unlock() // release lock
}()
}Or using defer to guarantee unlock:
go func() {
mu.Lock()
defer mu.Unlock()
counter++
}()Key points
Never forget to call Unlock; a missed unlock leads to a deadlock.
Lock granularity affects performance; keep critical sections short.
Typical scenario : protecting mutable shared state such as counters, maps, or file handles from race conditions.
Comparison
Goal : WaitGroup synchronizes the completion of goroutines; Mutex protects shared data during concurrent access.
When to use : Use WaitGroup when you need to wait for a set of tasks to finish. Use Mutex when multiple goroutines read/write the same variable.
Conclusion
Properly applying WaitGroup and Mutex enables safe and efficient concurrent programs in Go. They address different aspects of synchronization and are often combined: a WaitGroup can wait for all workers that each use a Mutex to protect shared resources.
References
Go official documentation: sync package
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Ops Development & AI Practice
DevSecOps engineer sharing experiences and insights on AI, Web3, and Claude code development. Aims to help solve technical challenges, improve development efficiency, and grow through community interaction. Feel free to comment and discuss.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
