Ответ
Нет, не гарантируется.
Если несколько каналов в select
готовы к выполнению одновременно (т.е. можно прочитать или записать данные), Go выбирает один из них псевдослучайным образом. Это не FIFO (First-In, First-Out) и не LIFO (Last-In, First-Out).
Такое поведение введено намеренно для обеспечения справедливости (fairness) и предотвращения голодания (starvation), когда один из каналов мог бы постоянно перехватывать все операции, если бы у него был более высокий приоритет.
Пример:
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
ch1 <- "from ch1"
}()
go func() {
ch2 <- "from ch2"
}()
time.Sleep(10 * time.Millisecond) // Даем горутинам время на отправку
// При многократном запуске вывод будет меняться
for i := 0; i < 2; i++ {
select {
case msg1 := <-ch1:
fmt.Println("Received", msg1)
case msg2 := <-ch2:
fmt.Println("Received", msg2)
}
}
}
Как задать приоритет?
Если вам нужен приоритетный выбор, вы можете использовать select
с блоком default
для неблокирующей проверки более приоритетного канала. Если он не готов, можно проверять остальные.
// Пытаемся прочитать из priorityCh без блокировки
select {
case msg := <-priorityCh:
fmt.Println("High priority message:", msg)
default:
// priorityCh не готов, проверяем другие каналы
select {
case msg := <-priorityCh:
fmt.Println("High priority message:", msg)
case msg := <-normalCh:
fmt.Println("Normal priority message:", msg)
case <-time.After(100 * time.Millisecond):
fmt.Println("No messages received.")
}
}