← Back to Go Course | Chapter 11: Concurrency | Lesson 4 of 8

The select Statement

select is like waiting at several doors at once, and stepping through whichever one opens first.

Waiting on Multiple Channels

select blocks until one of its listed channel operations can proceed, then runs that case's body -- it's how a goroutine can respond to whichever of several channels produces a value first.

Example: Waiting on Multiple Channels

markup
package main

import "fmt"

func main() {
	ch1 := make(chan string, 1)
	ch2 := make(chan string, 1)
	ch1 <- "from channel one"

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

Non-Blocking select with default

Adding a default case makes select non-blocking: if no other case is immediately ready, the default branch runs right away instead of waiting.

Example: Non-Blocking select with default

markup
package main

import "fmt"

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

Timeouts with select and time.After

Combining select with time.After lets a goroutine give up waiting on a channel after a deadline, which is the standard Go pattern for adding timeouts to blocking operations.

Example: Timeouts with select and time.After

markup
package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan string)
	select {
	case msg := <-ch:
		fmt.Println(msg)
	case <-time.After(50 * time.Millisecond):
		fmt.Println("timed out waiting for a value")
	}
}
Common Mistakes
  1. Assuming select checks cases in order like a switch -- when multiple cases are ready, Go picks one at random, not top-to-bottom.
  2. Writing a select with no default and no case ever becoming ready, causing the goroutine to block forever.
  3. Forgetting a default case makes select non-blocking, immediately falling through if no channel is ready.
Chapter Summary
  • select lets a goroutine wait on multiple channel operations at once.
  • When multiple cases are ready simultaneously, select picks one at random -- there's no priority order.
  • A default case makes select non-blocking, running immediately if no channel is ready.
  • select is commonly used with time.After to implement timeouts on channel operations.
🔒

Chapter Quiz — Complete all 8 topics to unlock

0/8 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.