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:

  1. Goroutines are lightweight threads (not OS threads)

  2. Channels provide safe communication between goroutines

  3. 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

  1. Fan-out/Fan-in: Multiple goroutines process work, one collects results

  2. Worker Pool: Fixed number of workers process jobs from a queue

  3. Pipeline: Chain of goroutines connected by channels

  4. Context Cancellation: Gracefully stop goroutines

Producer-Consumer Example

See Producer-Consumer for a Go implementation demonstrating goroutines, channels, and wait groups.