100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Go

The select Statement in Go

The select statement lets a goroutine wait on multiple channel operations at once, proceeding with whichever is ready first.

ConcurrencyIntermediate8 min readJul 8, 2026
Analogies

Introduction

The select statement is Go's way of waiting on multiple channel operations simultaneously. It looks similar to a switch, but each case is a channel send or receive rather than a value comparison. select blocks until one of its cases can proceed; if multiple are ready at the same time, Go picks one at random, which prevents starvation and keeps the choice unbiased. This makes select essential for building responsive concurrent code that reacts to whichever event happens first.

🏏

Cricket analogy: A captain watching both ends of the pitch during a run-chase reacts to whichever event happens first, a boundary or a run-out chance, rather than fixating on one end; select waits on multiple channels and fires whichever is ready first, picking randomly among ties to stay fair.

Syntax

go
select {
case v := <-ch1:
    // use v received from ch1
case ch2 <- x:
    // sent x on ch2
case <-time.After(2 * time.Second):
    // timeout branch
default:
    // runs immediately if no other case is ready (non-blocking select)
}

Explanation

Each case in a select attempts a channel operation. Go evaluates all cases and blocks until at least one is ready to proceed; if several are ready simultaneously, one is chosen uniformly at random. Including a default case turns select into a non-blocking operation: if no channel is ready right away, default runs instead of waiting. A very common pattern combines select with time.After(duration), which returns a channel that receives a value after the given duration, giving you a built-in way to implement timeouts on channel operations without extra goroutines.

🏏

Cricket analogy: A fielding captain with a default fallback plan, keep bowling normally if no review request comes in within seconds, mirrors select's default case running immediately when no channel is ready, avoiding any wait.

Example

go
package main

import (
    "fmt"
    "time"
)

func worker(ch chan<- string) {
    time.Sleep(1 * time.Second)
    ch <- "work done"
}

func main() {
    resultCh := make(chan string)
    go worker(resultCh)

    select {
    case res := <-resultCh:
        fmt.Println("Result:", res)
    case <-time.After(500 * time.Millisecond):
        fmt.Println("Timed out waiting for result")
    }
}

Output

Timed out waiting for result Since the worker sleeps for 1 second but the timeout fires after 500 milliseconds, the time.After case becomes ready first, and select chooses that branch.

🏏

Cricket analogy: When the third umpire's review clock lapses before the replay analysis is done, the on-field decision stands by default; here the 500ms timeout channel becomes ready before the 1-second worker finishes, so select picks the timeout branch.

Key Takeaways

  • select waits on multiple channel send/receive operations and proceeds with whichever becomes ready.
  • If multiple cases are ready at once, Go picks one at random to avoid starvation.
  • A default case makes select non-blocking, useful for polling channels.
  • time.After(duration) combined with select is the idiomatic way to implement timeouts.
  • select is central to building responsive, event-driven concurrent Go programs.

Practice what you learned

Was this page helpful?

Topics covered

#Go#GoProgrammingStudyNotes#Programming#TheSelectStatementInGo#Select#Statement#Syntax#Explanation#StudyNotes#SkillVeris