Skip to content

Chapter 08: Concurrency ​

"Concurrency is not Parallelism." - Rob Pike

Up until now, your code did one thing at a time. It was a single worker. But real shops start doing many things at once. One clerk checks credentials, another fetches the product, a third calculates shipping.

The Go runtime schedules goroutines on operating-system threads. Goroutine stacks can grow; memory costs depend on the runtime and workload. Bound concurrent work according to measured CPU, memory, and downstream limits.

1 The Worker (Goroutine) ​

To start a task in the background, just put go in front of it.

go
func main() {
    go sendEmail("Welcome!") // Leaves immediately!
    fmt.Println("Done")
}

This spawns a new "Elf" to do the work. The main function doesn't wait for him. It finishes and exits. Warning: If main dies, all Elves die instantly, even if they aren't finished.

2 The Conveyor Belt (Channels) ​

If Elves work silently, how do they talk? They use Channels. Think of a Channel as a pipe. One Elf puts data in one end, another takes it out the other.

go
ch := make(chan string)
go func() {
    ch <- "Job Done!" // Send
}()
msg := <-ch // Receive (Waits until data arrives)

2.1 The Visual Signal (The Conveyor Belt) ​

Concept: Safe communication between concurrent Goroutines. Signal: A Factory Conveyor Belt. Workers (Goroutines) put items on, other workers take them off. No one fights over the item; the belt manages the handoff.

3 The Worker Pool (The Shop Floor) ​

Imagine 1,000 customers click "Buy" at once. If you start 1,000 background jobs, you might crash the server. Instead, we use a Buffered Channel as a waiting line.

  1. Handler: May report that a demonstration job was queued. A channel in RAM loses pending jobs on process exit; enqueueing is not proof of payment, persisted order, or delivery. A real order must be stored durably before acknowledgement, with retry and deduplication rules.
  2. Queue: Holds orders until the Worker is ready (Buffer).
  3. Worker: Processes orders one by one (or in a pool).

4 The Toilet Lock (Mutex) ​

Sometimes, two workers need to use the same resource (like a map or a counter). If they touch it at the same time, data gets corrupted (Race Condition). We need a lock. In Go, it's sync.Mutex.

Think of it like a Toilet Door.

  1. Lock(): You enter and lock the door. Everyone else waits outside.
  2. Unlock(): You leave. The next person can enter.
go
mu.Lock()
count++ // Safe zone
mu.Unlock()
🎓 Knowledge Check: What is a Race Condition?

Answer: A data race involves unsynchronized accesses to the same memory with at least one write; a read racing with a write also counts. Protect all relevant accesses with synchronization. A higher-level race condition can exist even without a data race, such as separately checking and then changing a balance.

Released under the MIT License.