Skip to content
Francisco Cidade
5 min read

(WIP) Concurrency and Parallelism in Go - Select

Summary

Select

alt text

select is a powerful tool for managing multiple channels in Go, letting you wait on I/O operations and avoid unnecessary blocking. Understanding its syntax, the importance of default and the behavior when multiple cases are ready is essential to writing robust concurrent code.

What is select?

Syntax

When to use select

Practical example

Consider two channels; we want to wait for data from either of them:

package main

import (
	"fmt"
	"time"
)

func main() {
	ch1 := make(chan string)
	ch2 := make(chan string)
	
	// Simulating data being sent after different delays
	go func() {
		time.Sleep(500 * time.Millisecond)
		ch1 <- "Message from channel 1"
	}()
	
	go func() {
		time.Sleep(300 * time.Millisecond)
		ch2 <- "Message from channel 2"
	}()
	
	// select waits until one of the channels is ready to send data
	select {
		case msg1 := <-ch1:
			fmt.Println("Received:", msg1)
		case msg2 := <-ch2:
			fmt.Println("Received:", msg2)
		default:
			fmt.Println("No channel was ready.")
	}
	
	// The program can wait a bit to see the full execution
	time.Sleep(1 * time.Second)
}

In this example, because of the sleep times, the ch2 case will fire first, but the default would run immediately if no channel were ready.

Using default

Exercises with select

Exercise 1 – Receiving from the first available channel

Exercise 2 – Send and default

Exercise 3 – Timeout with select

Exercise 4 – Alternating between multiple channels

Exercise 5 – Combination: select with waitgroup

Most common mistakes with select

Failing to include a default when needed

Assuming a deterministic order

Not handling closed channels

Using select badly in loops

Mixing blocking and non-blocking cases

Exercise solutions

So I wouldn’t have to run each exercise by hand, I used tests and testable examples.

Exercise 1:

// main.go
// main_test.go

Next steps!

Next we will cover Mutex! Click here for part 4!

References