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:

  1. Menangani multiple channel
  2. Implementasi timeout
  3. 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

  1. Basic Select

    • Multiple channel operations
    • Non-blocking
    • Random selection jika multiple ready
  2. Select Features

    • Timeout handling
    • Default case
    • Channel direction
  3. 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