Select Statement in Go Language (original) (raw)
Last Updated : 11 Jul, 2025
In Go, the select statement allows you to wait on multiple channel operations, such as sending or receiving values. Similar to a switch statement, select enables you to proceed with whichever channel case is ready, making it ideal for handling asynchronous tasks efficiently.
Example
Consider a scenario where two tasks complete at different times. We’ll use select to receive data from whichever task finishes first.
Go `
package main import ( "fmt" "time" ) func task1(ch chan string) { time.Sleep(2 * time.Second) ch <- "Task 1 completed" }
func task2(ch chan string) { time.Sleep(4 * time.Second) ch <- "Task 2 completed" }
func main() { ch1 := make(chan string) ch2 := make(chan string)
go task1(ch1)
go task2(ch2)
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
}}
`
**Note: After 2 seconds,
Task 1 completedwill be printed becausetask1completes beforetask2. Iftask2finished first, thenTask 2 completedwould be printed.
Syntax
The select statement in Go listens to multiple channel operations and proceeds with the first ready case.
select { case value := <-channel1: // Executes if channel1 is ready to send/receive case channel2 <- value: // Executes if channel2 is ready to send/receive default: // Executes if no other case is ready }
Key Points:
selectwaits until at least one channel operation is ready.- If multiple cases are ready, one is chosen at random.
- The
defaultcase executes if no other case is ready, avoiding a block.
Table of Content
Select Statement Variations
Basic Blocking Behavior
In this variation, we modify the earlier example by removing the select statement and observe blocking behavior when no channels are ready.
**Example
Go `
package main import ( "fmt" ) func main() { ch := make(chan string)
select {
case msg := <-ch:
fmt.Println(msg)
default:
fmt.Println("No channels are ready")
}}
`
Output
No channels are ready
**Explanation: Here, the
defaultcase ensures thatselectdoesn’t block if no channels are ready, printing"No channels are ready".
Handling Multiple Cases
If both tasks are ready at the same time, select chooses one case randomly. This can happen if tasks have similar sleep times.
**Example
Go `
package main import ( "fmt" "time" ) func portal1(channel1 chan string) { time.Sleep(3 * time.Second) channel1 <- "Welcome to channel 1" } func portal2(channel2 chan string) { time.Sleep(9 * time.Second) channel2 <- "Welcome to channel 2" } func main() { R1 := make(chan string) R2 := make(chan string) // calling function 1 and function 2 in goroutine go portal1(R1) go portal2(R2) select { // case 1 for portal 1 case op1 := <-R1: fmt.Println(op1) // case 2 for portal 2 case op2 := <-R2: fmt.Println(op2) } }
`
Output
Welcome to channel 1
**Explanation: In this scenario,
selectrandomly picks one of the two cases if both are ready at the same time, meaning you may see"Task 1 completed"or"Task 2 completed"depending on the selection.
Using Select with Default Case to Avoid Blocking
Using default ensures the program does not block if no case is ready. Here’s an example modifying the base structure to include a default case.
**Example
Go `
package main import ( "fmt" ) func main() { ch1 := make(chan string) ch2 := make(chan string)
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
default:
fmt.Println("No tasks are ready yet")
}}
`
Output
No tasks are ready yet
**Explanation: Since neither
ch1norch2is ready, thedefaultcase executes, outputting"No tasks are ready yet".
Infinite Blocking without Cases
If a select statement is empty (i.e., contains no cases), it blocks indefinitely. This is often used in cases where an infinite wait is necessary, but here’s what it looks like using our channels.
Go `
package main
func main() { select {} // This blocks forever as there are no cases }
`
**Explanation: Since there are no cases, select will block permanently, causing a deadlock if there are no other goroutines active.