Recipe

Go select statement primer

The select statement is Go's concurrency multiplexer. It lets a goroutine wait on multiple channel operations and proceed with whichever is ready first. This primer covers the three patterns you reach for daily: blocking selects, non-blocking polls with default, and timeout guards.

1.Blocking on the first ready channel

With no default case, select blocks until exactly one case can proceed. When multiple cases are ready simultaneously, Go picks one pseudo-randomly to prevent starvation.

2.Non-blocking polls with default

Adding a default branch turns the select into a poll. If no channel is ready, the default runs immediately. Use this for opportunistic sends or hot-loop drain patterns where you must never block.

3.Timeout guards with time.After

Pair your work channel with time.After(d) to bound how long a goroutine waits. For long-running deadlines prefer context.Context so cancellation propagates across call boundaries.

select {
case msg := <-jobs:
    handle(msg)
case <-ctx.Done():
    return ctx.Err()
case <-time.After(2 * time.Second):
    return errors.New("timeout")
default:
    runtime.Gosched()
}