Questions
What is the `select` statement and what is it used for in Go?
The Scenario
You are a backend engineer at a social media company. You are writing a new service that needs to listen for messages on multiple channels at the same time.
You need to find a way to process the messages as they come in, without blocking the other channels.
The Challenge
Explain what the select statement is in Go and how you would use it to solve this problem. What are the key benefits of using the select statement?
A junior engineer might try to solve this problem by using a separate goroutine for each channel. This would work, but it would be more complex than it needs to be.
A senior engineer would know that the `select` statement is the perfect tool for this job. They would be able to explain what the `select` statement is and how to use it to listen for messages on multiple channels at the same time.
Step 1: Understand What the select Statement Is
The select statement is a control structure that allows a goroutine to wait on multiple communication operations.
A select statement blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready.
Step 2: Use select to Listen on Multiple Channels
Here’s how we can use the select statement to listen for messages on multiple channels:
package main
import (
"fmt"
"time"
)
func main() {
c1 := make(chan string)
c2 := make(chan string)
go func() {
time.Sleep(1 * time.Second)
c1 <- "one"
}()
go func() {
time.Sleep(2 * time.Second)
c2 <- "two"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
}
}
}In this example, the select statement will block until a message is received on either c1 or c2.
The default Case
You can use a default case to prevent the select statement from blocking if none of the other cases are ready.
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
default:
fmt.Println("no message received")
}Timeouts
You can use a time.After channel to implement a timeout in a select statement.
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case <-time.After(1 * time.Second):
fmt.Println("timeout")
} Practice Question
You have a `select` statement with multiple cases that are ready to run. What will happen?