Learn Go← Dashboard

Go's typed pipes — communicate, don't share memory.

select

select is like switch — but for channel operations. Each case is either a send or a receive on some channel. select blocks until one of them can proceed, then runs that case. If multiple are ready, it picks one randomly.

A first select

go playground
Loading...

Timeouts with time.After

time.After(d) returns a channel that delivers the current time after d. Drop it into a select and you've got a timeout:

go playground
Loading...

For real code, prefer context.WithTimeout (see chapter 20) over manual time.After.

Non-blocking with default

A default case runs when no other case is ready. Use it for non-blocking sends and receives.

select {
case work := <-jobs:
    process(work)
default:
    // no work right now — do something else
}

select {} — block forever

A select with no cases blocks forever. Useful in main when all the real work is in goroutines.

func main() {
    go serve()
    select {} // sit here until something kills us
}

Disabling a case at runtime

A nil channel never fires in a select — its case is silently skipped. This lets you turn cases on and off dynamically:

var input <-chan job = jobs   // active

if shuttingDown {
    input = nil                // disable this case
}

select {
case j := <-input:
    process(j)
case <-ctx.Done():
    return
}
In a `select`, if two cases are both ready at the same instant, which one runs?