CHAPTER 21
Beginner
Advanced Concurrency Patterns
Updated: May 17, 2026
5 min read
# CHAPTER 21
Advanced Concurrency Patterns
1. Introduction
While single Goroutines and Channels are powerful, enterprise applications require complex orchestration. You might need to query 3 databases simultaneously and return whichever responds first, or spawn 100 worker threads to process a massive CSV file and wait for all of them to finish. To achieve this, Go provides thesync package and the select statement.
2. Learning Objectives
By the end of this chapter, you will be able to:-
Use
sync.WaitGroupto wait for a fleet of Goroutines to finish.
-
Listen to multiple channels simultaneously using
select.
- Understand the Worker Pool pattern.
- Identify Race Conditions.
-
Use
sync.Mutexto lock shared memory safely.
3. Synchronizing with sync.WaitGroup
If you spawn 10 Goroutines, main() will exit before they finish. Using time.Sleep is a terrible idea. Using 10 channels just to wait is messy.
sync.WaitGroup acts like a counter. You add to the counter before spawning a Goroutine, subtract from it when the Goroutine finishes, and tell main to wait until the counter hits zero.
go
4. Multiplexing with the select Statement
Imagine you make requests to two external APIs (API 1 and API 2) concurrently. You want to proceed as soon as the *first* one responds, ignoring the slower one.
The select statement looks like a switch, but it exclusively monitors Channels. It blocks until *one* of its cases is ready.
go
5. Race Conditions
A Race Condition occurs when two Goroutines try to read and write to the *exact same variable in memory* at the exact same time. The data gets corrupted.*Scenario:* Two bank transactions try to deposit $5 into an account that has $10 simultaneously. Both read $10, both add $5, both write $15. The final balance should be $20, but it is corrupted to $15!
6. Memory Locking with sync.Mutex
While Go prefers Channels, sometimes you just need to update a shared variable. A Mutex (Mutual Exclusion) acts like a lock on a bathroom door. A Goroutine locks the door, updates the variable, and unlocks it. If another Goroutine arrives while the door is locked, it waits in line.
go
7. Common Mistakes
-
Passing WaitGroup by Value: If you write
go worker(i, wg)instead ofgo worker(i, &wg), you pass a *copy* of the WaitGroup. When the worker calls.Done(), it decrements the copy, not the original.mainwill Wait() forever (Deadlock).
-
Forgetting to Unlock a Mutex: If a Goroutine panics or returns early before calling
c.mu.Unlock(), the lock remains closed forever, and all other Goroutines will freeze indefinitely. Always usedefer c.mu.Unlock()!
8. Best Practices
-
Test for Race Conditions: Go has a built-in tool to detect memory corruption. Run your code using
go run -race main.go. If there are any race conditions, the compiler will aggressively warn you!
9. Exercises
-
1.
Write a program that uses a
sync.WaitGroup.
- 2. Spawn 5 Goroutines that simply print "Processing...".
-
3.
Ensure
mainwaits for all 5 to finish before printing "Done".
10. MCQs with Answers & Explanations
Question 1
What is the purpose of sync.WaitGroup?
Question 2
What are the three methods used with a WaitGroup?
Question 3
How must a WaitGroup be passed into a Goroutine?
Question 4
What does the select statement do?
Question 5
If multiple cases in a select statement become ready at the exact same millisecond, what happens?
Question 6
What is a Race Condition?
Question 7
What does sync.Mutex stand for?
Question 8
How does a Mutex solve race conditions?
Question 9
Which terminal command flags your code to check for memory corruption bugs?
Question 10
What is the safest way to ensure a Mutex unlocks, even if the function encounters an error?
11. Interview Preparation
Interview Questions:-
1.
You have a slice of URLs and you want to download all of them concurrently, but you need
mainto wait until they are all downloaded. How do you architect this? (Answer: WaitGroup).
- 2. Explain the difference between using Channels for synchronization vs using a Mutex. (Answer: Channels pass data ownership. Mutex locks shared state).
12. Summary
Enterprise Go code relies heavily on thesync package. WaitGroups orchestrate fleets of Goroutines cleanly. The select statement handles complex network timeouts and multi-channel routing. Finally, understanding Race Conditions and sync.Mutex ensures that your high-speed concurrent applications don't silently corrupt customer data.