What does the select statement do?

5 minintermediategoselectchannelsconcurrency

Quick Answer

select lets a goroutine wait on multiple channel operations at once, proceeding with whichever case becomes ready first. If multiple cases are ready simultaneously, Go picks one at random, which prevents any single channel from being unfairly starved. A default case makes the whole select non-blocking — it runs immediately if no other case is ready, instead of waiting. select is the standard tool for implementing timeouts (select on a work channel and a time.After channel), cancellation (select on a work channel and a context.Done() channel), and fan-in patterns that merge multiple input channels into one.

Detailed Answer

select is Go's multiplexer for channel operations, and it shows up constantly in real concurrent code.

Waiting on the first of several channels

select {
case v := <-ch1:
    fmt.Println("from ch1:", v)
case v := <-ch2:
    fmt.Println("from ch2:", v)
}

Whichever channel has a value ready first wins. If both are ready at the same instant, Go picks randomly between them.

Implementing a timeout

select {
case result := <-workCh:
    fmt.Println("got result:", result)
case <-time.After(2 * time.Second):
    fmt.Println("timed out")
}

Non-blocking check with default

select {
case v := <-ch:
    fmt.Println("received:", v)
default:
    fmt.Println("no value ready, moving on")
}

Without default, this select would block until ch had a value. With it, the select returns immediately either way.

Cancellation with context

func worker(ctx context.Context, workCh <-chan int) {
    for {
        select {
        case <-ctx.Done():
            return   // caller cancelled, stop working
        case v := <-workCh:
            process(v)
        }
    }
}

This pattern, select between real work and a cancellation signal, is the standard way to make a long-running goroutine stoppable from the outside.

Related Resources