“Imagine you’re waiting for multiple things — whoever answers first, you talk to them!”
That’s exactly what select does in Go.
Let’s say you're messaging 3 friends:
Ali ⏳
Budi 💤
Chia ✅
You text all of them. Whoever replies first, you talk to them. You don’t wait for all — just the first response.
That’s what select does with channels: it waits for any one of them to send a value, and responds immediately.
select {
case msg1 := <-chan1:
fmt.Println("Received", msg1)
case msg2 := <-chan2:
fmt.Println("Received", msg2)
}It’s like:
“If
chan1has something, take it!”“Else if
chan2has something, take that!”
First one ready = winner.
package main
import (
"fmt"
"time"
)
func main() {
c1 := make(chan string)
c2 := make(chan string)
// Respond after different delays
go func() {
time.Sleep(1 * time.Second)
c1 <- "one"
}()
go func() {
time.Sleep(2 * time.Second)
c2 <- "two"
}()
select {
case msg1 := <-c1:
fmt.Println("Received", msg1)
case msg2 := <-c2:
fmt.Println("Received", msg2)
}
}
🧠 Output:
Received oneBecause c1 was faster.
Let’s say your friends don’t reply. You can give up after a few seconds!
select {
case msg := <-c:
fmt.Println("Got message", msg)
case <-time.After(3 * time.Second):
fmt.Println("Timeout! Nobody replied 😢")
}This prevents your program from hanging forever!
for {
select {
case msg := <-chan1:
fmt.Println("Got:", msg)
case <-time.After(time.Second):
fmt.Println("Still waiting...")
}
}This checks regularly and doesn't block too long.
Just want to check quickly if anything is ready? Use default:
select {
case msg := <-chan1:
fmt.Println("Got:", msg)
default:
fmt.Println("Nothing yet!")
}No blocking — it moves on instantly.
Use
selectto wait for first response from two goroutinesAdd a timeout after 2 seconds
Combine with pipelines!
selectlets you wait on multiple channelsIt reacts to whichever is ready first
Use
time.Afterfor timeoutsUse
defaultto avoid blocking
No posts

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.