HowtoGo
Home / Concurrency / Select
Concurrency

Select

Terms Select

select lets a goroutine wait on multiple channel operations at once, similar to switch but for channels. It blocks until one case can run, then runs that one.

A basic select with two channels. Whichever channel has a value ready first wins; if both are ready at the same instant, Go picks one at random.

select {
case msg1 := <-ch1:
    fmt.Println("received", msg1)
case msg2 := <-ch2:
    fmt.Println("received", msg2)
}

Add a default case to make select non-blocking. If no channel is ready, default runs immediately instead of waiting.

select {
case msg := <-ch:
    fmt.Println("received", msg)
default:
    fmt.Println("no message ready")
}

time.After returns a channel that fires once, after the given duration. Pairing it with select adds a timeout to any channel operation.

select {
case res := <-results:
    fmt.Println("received:", res)
case <-time.After(200 * time.Millisecond):
    fmt.Println("timed out")
}

Putting it together: a goroutine does some work and sends the result on a channel, while select races that against a 200ms timeout.

package main

import (
    "fmt"
    "time"
)

func main() {
    results := make(chan string)

    go func() {
        time.Sleep(50 * time.Millisecond)
        results <- "done"
    }()

    select {
    case res := <-results:
        fmt.Println("received:", res)
    case <-time.After(200 * time.Millisecond):
        fmt.Println("timed out")
    }
}

The goroutine finishes in 50ms, well under the 200ms timeout, so the results case wins.

Terminal
$ go run select.go
received: done