โšกGoroutines & ChannelsLESSON

Goroutines & Channels

Goroutines

A goroutine is a lightweight thread managed by the Go runtime. You start one by prefixing a function call with go:

Goroutines are extremely cheap โ€” you can spawn thousands without issue. The key point: if main returns, all goroutines are killed immediately.

Channels

Channels are typed conduits that let goroutines communicate safely. Create one with make:

Send a value with ch <- value, and receive with value := <-ch. Channels synchronize the sender and receiver โ€” both block until the other side is ready.

This example is complete and runnable: the main goroutine blocks on <-ch until sum sends its result.

Buffered Channels

A buffered channel accepts sends without a matching receiver โ€” up to its capacity:

Unbuffered channels block on every send until a receiver is ready. Buffered channels only block when the buffer is full (send) or empty (receive).

The select Statement

select is like a switch for channel operations โ€” it waits for whichever case is ready first:

If multiple cases are ready simultaneously, Go picks one at random. The default case runs immediately if no channel is ready, avoiding a block.

The Default Case in select

A default case makes channel operations non-blocking โ€” instead of waiting for a channel, Go immediately takes the default branch when no case is ready.

Try-receive pattern โ€” check if a value is available without blocking:

Try-send pattern โ€” drop a value rather than block when the channel is full:

Polling loop โ€” default combined with time.Sleep lets a goroutine periodically check a channel without ever blocking on it:

Typical use cases: rate limiting, circuit breakers, and checking whether a goroutine has finished without stalling the caller.

Range and Close

Closing a channel

close(ch) signals to receivers that no more values will be sent. Only the sender should close a channel โ€” closing a nil channel or closing one that is already closed will panic.

The comma-ok idiom

A receive expression returns a second boolean that tells you whether the channel is still open:

for range over a channel

for range handles the comma-ok check internally and stops the loop automatically when the channel is closed and empty:

This is the standard producer/consumer pattern: the producer goroutine closes the channel when it is done; the consumer uses for range rather than counting expected values.

Rules to avoid panics:

  • Never close a channel from the receiver side
  • Never close a channel more than once
  • If multiple goroutines may send, coordinate closure with a sync.WaitGroup and a dedicated closer goroutine

sync.WaitGroup

time.Sleep is a poor way to wait for goroutines. The idiomatic solution is sync.WaitGroup:

  • wg.Add(n) โ€” increment the counter by n before launching goroutines
  • wg.Done() โ€” decrement the counter (always use with defer)
  • wg.Wait() โ€” block until the counter reaches zero

Channel Directions

Function signatures can constrain a channel to send-only or receive-only, preventing accidental misuse:

SyntaxMeaning
chan TBidirectional (read and write)
chan<- TSend-only
<-chan TReceive-only

Directional channels improve safety and serve as documentation โ€” the signature tells you exactly how the channel is used.

sync.Mutex

When multiple goroutines share mutable state, protect it with a sync.Mutex:

The defer c.mu.Unlock() pattern ensures the mutex is always released, even if the function returns early or panics.

Goroutine Leaks

A goroutine that is never able to complete is a goroutine leak โ€” it consumes memory and CPU indefinitely. The most common cause is a goroutine blocked on a channel receive when no sender will ever send:

To prevent leaks: always ensure goroutines have a way to exit โ€” use a done channel, a context.Context cancellation, or close the channel when work is complete.

Knowledge Check

In a channel type `chan<- int`, what does `chan<-` mean?

What does a `select` statement do?

What happens when a select statement has a default case and no channel is ready?