Skip to content

Select

The select statement in Go is used to handle multiple channel operations concurrently. It blocks until one of the operations can proceed. This is particularly useful when you have multiple goroutines communicating via channels and you want to handle their messages as they arrive. You can also use the default case in a select statement to prevent blocking. If none of the cases are ready, the default case will be executed.

Example

We then use a select statement to receive data from either channel. In this case, it will print the data received from the number channel because this channel is ready first.

run command
go run src/multithereading/basic_select.go
package main

import (
    "fmt"
    "time"
)

func main() {
    number := make(chan int)
    message := make(chan string)

    go channelNumber(number)
    go channelMessage(message)

    select {
    case firstChannel := <-number:
        fmt.Println("Channel Data:", firstChannel)

    case secondChannel := <-message:
        fmt.Println("Channel Data:", secondChannel)
    }
}

func channelNumber(number chan int) {
    number <- 15
}

func channelMessage(message chan string) {
    time.Sleep(2 * time.Second)
    message <- "Learning Go Select"
}
output
Channel Data: 15

Default

run command
go run src/multithereading/default_select.go
package main

import (
    "fmt"
    "log"
    "time"
)

func main() {

    ch := make(chan int)

    go func() {
        for i := 0; i < 3; i++ {
            time.Sleep(2 * time.Second)
            ch <- 1
        }
    }()

    for i := 0; i < 10; i++ {
        time.Sleep(time.Second)
        select {
        case num := <-ch:
            fmt.Printf("Number received: %d\n", num)
        default:
            log.Println("Default")
        }
    }
}
output
...
2023/12/20 12:13:12 Default
Number received: 1
2023/12/20 12:13:14 Default
Number received: 1
2023/12/20 12:13:16 Default
2023/12/20 12:13:17 Default
Number received: 1
2023/12/20 12:13:19 Default
2023/12/20 12:13:20 Default
2023/12/20 12:13:21 Default

More Complex example

run command
go run src/multithereading/select.go
package main

import (
    "fmt"
    "log"
    "sync/atomic"
    "time"
)

type Message struct {
    id  int32
    Msg string
}

var countId int32 = 0

func rabbitMQMessage(ch chan<- Message) {
    // Infity loop
    for {
        atomic.AddInt32(&countId, 1)
        msg := Message{countId, fmt.Sprintf("Message %d from RabbitMQ", countId)}
        ch <- msg
        if countId > 8 {
            time.Sleep(4 * time.Second)
        }
    }
}

func kafkaMessage(ch chan<- Message) {
    // Infity loop
    for {
        atomic.AddInt32(&countId, 1)
        msg := Message{countId, fmt.Sprintf("Message %d from Kafka", countId)}
        ch <- msg
        if countId > 4 {
            time.Sleep(4 * time.Second)
        }
    }
}

func main() {
    ch1 := make(chan Message)
    ch2 := make(chan Message)

    go rabbitMQMessage(ch1)
    go kafkaMessage(ch2)

    for i := 0; i < 20; i++ {
        select {
        case msg := <-ch1:
            fmt.Printf("Received from ch1: ID: %d - %s\n", msg.id, msg.Msg)
        case msg := <-ch2:
            fmt.Printf("Received from ch2: ID: %d - %s\n", msg.id, msg.Msg)
        case <-time.After(time.Second * 2):
            log.Print("timeout")
        }
    }

}
output
...
Received from ch2: ID: 1 - Message 1 from Kafka
Received from ch2: ID: 2 - Message 2 from Kafka
Received from ch2: ID: 4 - Message 4 from Kafka
Received from ch2: ID: 5 - Message 5 from Kafka
Received from ch1: ID: 5 - Message 3 from RabbitMQ
Received from ch1: ID: 6 - Message 6 from RabbitMQ
Received from ch1: ID: 7 - Message 7 from RabbitMQ
Received from ch1: ID: 8 - Message 8 from RabbitMQ
Received from ch1: ID: 9 - Message 9 from RabbitMQ
2023/12/20 12:05:49 timeout
2023/12/20 12:05:51 timeout
Received from ch1: ID: 10 - Message 10 from RabbitMQ
Received from ch2: ID: 11 - Message 11 from Kafka
2023/12/20 12:05:53 timeout
Received from ch2: ID: 12 - Message 12 from Kafka
Received from ch1: ID: 13 - Message 13 from RabbitMQ
2023/12/20 12:05:57 timeout
Received from ch1: ID: 14 - Message 14 from RabbitMQ
Received from ch2: ID: 15 - Message 15 from Kafka
2023/12/20 12:06:01 timeout

References

  1. Go Select
  2. How To Effectively Utilize Golang Select In Your Projects