liveBook · Manning

Select statement

As explained in Learn Go with Pocket-Sized Projects

A select statement is a Go control-flow construct that chooses among channel send, channel receive, and optional default cases that are ready to proceed.

A Go select statement lets a goroutine wait on several channel operations at once. Each case sends to or receives from a channel; an eligible case runs, and the others are skipped. If several are eligible, Go chooses one at random. section 9.5.2

Consider a maze solver that launches workers for new paths but must stop when a worker finds the solution. Put select inside a for loop so the dispatcher can keep receiving paths while also listening for a quit signal. A quit case returns from the loop. section 9.5.2 section 9.7

Listing 9.26 explore.go: Stop listening to new messages
func (s *Solver) listenToBranches() {
    wg := sync.WaitGroup{}
    defer wg.Wait()

    for {
        select {
        case <-s.quit: #1
            log.Println("the treasure has been found, stopping worker")
            return
        case p := <-s.pathsToExplore: #2
            wg.Add(1)
            go func(p *path) {
                defer wg.Done()

                s.explore(p)
            }(p)
        }
    }
}

The dispatcher handles either a quit signal or a path to explore. Its wait group keeps track of workers already launched. section 9.5.2

A default case can make a quick quit check before continuing exploration. But checking quit and then sending a branch as separate operations leaves a gap: quit may arrive between them. Put the branch send in the select instead, so the worker waits for either cancellation or a possible send. Neither case has priority when both are ready. section 9.5.2

select {
case <-s.quit:
    log.Printf("I'm an unlucky branch, someone else found the treasure, I 
give up at position %v.", pos)
    return
case s.pathsToExplore <- branch:
    //continue execution after the select block

}

This alternative selects between receiving the quit signal and sending the next branch. section 9.5.2

With no cases at all, select {} blocks forever. One use is keeping a Go WebAssembly program alive after it registers a function that JavaScript will call later. section 12.2.2

How Learn Go with Pocket-Sized Projects covers it

How deep it goes
Explains channel cases, random choice among eligible cases, for-select loops, default checks, and guarded sends without descending into runtime internals.
Examples
Shows a maze dispatcher selecting between paths and quit, an explorer selecting between sending and quitting, and an empty select.
What it assumes
Assumes Go loops, goroutines, and channel reads; introduces select through the problem of listening to two channels.
What you can do after
Practice/perform it by writing Go select loops that respond to cancellation while dispatching work.
How it connects
Connects channels, goroutines, cancellation, for loops, data races, and WebAssembly callbacks.

Also explained in

Compare how 9 books explain select statement →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Go with Pocket-Sized Projects. The section links point to the parts of the book it draws on.