Why Go for Concurrency?
Python has the GIL (Global Interpreter Lock) which prevents true parallel execution of Python threads. While Python’s asyncio handles I/O-bound concurrency well, CPU-bound parallelism is limited.
Go was designed from the ground up for concurrency with goroutines and channels. This chapter uses Go to teach concurrency concepts because:
-
Goroutines are lightweight threads (not OS threads)
-
Channels provide safe communication between goroutines
-
The syntax is clean and concurrency patterns are idiomatic
|
Google interview context: Concurrency questions at L5 are rare in coding interviews (more common in system design). But understanding goroutines, mutexes, and deadlocks shows depth. If asked, you can say: "Python has the GIL which limits true parallelism. For CPU-bound concurrent work, I’d use Go’s goroutines or Python’s multiprocessing module." |
Core Concepts
Goroutines
func main() {
// Launch a goroutine — runs concurrently with main()
go func() {
fmt.Println("Hello from goroutine!")
}()
// Main goroutine continues here
fmt.Println("Hello from main!")
time.Sleep(time.Second) // Wait for goroutine to finish
}
Channels
func main() {
// Create a channel that carries integers
ch := make(chan int)
// Sender goroutine
go func() {
ch <- 42 // Send value into channel (blocks until receiver is ready)
}()
// Receive from channel (blocks until sender sends)
value := <-ch
fmt.Println(value) // 42
}
Common Patterns
-
Fan-out/Fan-in: Multiple goroutines process work, one collects results
-
Worker Pool: Fixed number of workers process jobs from a queue
-
Pipeline: Chain of goroutines connected by channels
-
Context Cancellation: Gracefully stop goroutines
Producer-Consumer Example
See Producer-Consumer for a Go implementation demonstrating goroutines, channels, and wait groups.