Select
Select adalah statement khusus di Go yang memungkinkan goroutine menunggu operasi pada multiple channel. Select mirip dengan switch, tapi untuk channel.
Contoh Masalah
Bagaimana cara:
- Menangani multiple channel
- Implementasi timeout
- Menghindari blocking
Penyelesaian
package main
import (
"fmt"
"time"
)
// 1. Function yang mengirim data ke channel dengan delay
func sender1(ch chan<- string) {
for i := 0; ; i++ {
ch <- fmt.Sprintf("Message from sender1: %d", i)
time.Sleep(100 * time.Millisecond)
}
}
func sender2(ch chan<- string) {
for i := 0; ; i++ {
ch <- fmt.Sprintf("Message from sender2: %d", i)
time.Sleep(150 * time.Millisecond)
}
}
// 2. Function dengan timeout
func process(ch chan<- string) {
time.Sleep(2 * time.Second)
ch <- "Process completed"
}
// 3. Function yang mengirim dan menerima
func worker(input <-chan int, output chan<- int) {
for {
select {
case n := <-input:
output <- n * 2
}
}
}
func main() {
// Contoh 1: Basic select
ch1 := make(chan string)
ch2 := make(chan string)
go sender1(ch1)
go sender2(ch2)
fmt.Println("Basic select example:")
for i := 0; i < 5; i++ {
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
}
}
// Contoh 2: Select dengan timeout
fmt.Printf("\nSelect dengan timeout:\n")
ch := make(chan string)
go process(ch)
select {
case result := <-ch:
fmt.Println(result)
case <-time.After(1 * time.Second):
fmt.Println("Process timeout")
}
// Contoh 3: Select dengan default
fmt.Printf("\nSelect dengan default:\n")
ch3 := make(chan string)
go func() {
time.Sleep(500 * time.Millisecond)
ch3 <- "Delayed message"
}()
for i := 0; i < 5; i++ {
select {
case msg := <-ch3:
fmt.Println(msg)
return
default:
fmt.Println("No message received")
time.Sleep(100 * time.Millisecond)
}
}
// Contoh 4: Select untuk multiple workers
fmt.Printf("\nMultiple workers example:\n")
input := make(chan int)
output := make(chan int)
// Start workers
for i := 0; i < 3; i++ {
go worker(input, output)
}
// Send work
go func() {
for i := 1; i <= 5; i++ {
input <- i
}
}()
// Collect results with timeout
timeout := time.After(1 * time.Second)
for i := 0; i < 5; i++ {
select {
case result := <-output:
fmt.Printf("Result: %d\n", result)
case <-timeout:
fmt.Println("Collection timeout")
return
}
}
// Contoh 5: Select untuk cancellation
fmt.Printf("\nCancellation example:\n")
done := make(chan bool)
messagesCh := make(chan string)
// Start sender
go func() {
for i := 0; ; i++ {
select {
case <-done:
return
case messagesCh <- fmt.Sprintf("Message %d", i):
time.Sleep(100 * time.Millisecond)
}
}
}()
// Receive for a while then cancel
for i := 0; i < 3; i++ {
msg := <-messagesCh
fmt.Println(msg)
}
done <- true
fmt.Println("Sender cancelled")
}
Penjelasan Kode
Basic Select
- Multiple channel operations
- Non-blocking
- Random selection jika multiple ready
Select Features
- Timeout handling
- Default case
- Channel direction
Common Patterns
- Worker pools
- Cancellation
- Rate limiting
Output
Basic select example:
Message from sender1: 0
Message from sender2: 0
Message from sender1: 1
Message from sender2: 1
Message from sender1: 2
Select dengan timeout:
Process timeout
Select dengan default:
No message received
No message received
No message received
No message received
Delayed message
Multiple workers example:
Result: 2
Result: 4
Result: 6
Result: 8
Result: 10
Cancellation example:
Message 0
Message 1
Message 2
Sender cancelled
Tips
- Gunakan timeout untuk operasi yang bisa lama
- Selalu sediakan mekanisme cancellation
- Default case untuk non-blocking
- Perhatikan goroutine leaks
- Select bisa digunakan dalam loop