Lesson 12: Concurrency¶
Big Picture¶
sequenceDiagram
participant M as main goroutine
participant W as worker goroutine
participant C as channel
M->>W: go worker(ch)
M->>C: ch <- job
C->>W: job := <-ch (blocks until send)
W->>C: ch <- result
C->>M: res := <-ch
Note over M,W: WaitGroup waits for Done<br/>Mutex guards shared state
Goroutines are cheap threads managed by the Go runtime; channels let them communicate safely — "don't communicate by sharing memory; share memory by communicating." select multiplexes channel ops; WaitGroup/Mutex cover the cases channels don't.
Concepts¶
Goroutines¶
Channels¶
ch := make(chan int) // Unbuffered
ch := make(chan int, 10) // Buffered
ch <- value // Send
value := <-ch // Receive
close(ch) // Close
Select¶
select {
case msg := <-ch1:
// Handle ch1
case ch2 <- value:
// Send to ch2
case <-time.After(time.Second):
// Timeout
default:
// Non-blocking
}
Synchronization¶
// WaitGroup
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
// work
}()
wg.Wait()
// Mutex
var mu sync.Mutex
mu.Lock()
// critical section
mu.Unlock()
Code Walkthrough¶
Full program: code/12_concurrency.go.
Race conditions
Run with the race detector to flag unsynchronized shared access:
Exercises
- Write a worker pool: N goroutines read jobs from one channel.
- Add a
time.Aftertimeout to aselectreceiving from a slow channel. - Build a counter incremented by 1000 goroutines — once unsynchronized (watch it fail with
-race), then with aMutex, then with a channel.
Check Your Understanding¶
#
What does an unbuffered channel send ch <- v do if no one is receiving?
#
Which tools prevent goroutine races? (select all)