Ответ
Оператор select
в Go позволяет горутине ждать нескольких операций связи. Его поведение при выборе case
следующее:
- Если готов только один
case
: Выполняется именно он. - Если готовы несколько
case
: Выбирается один из них псевдослучайным образом. Это ключевая особенность, которая обеспечивает справедливость (fairness) и предотвращает ситуацию, когда один канал постоянно "перехватывает" все операции, приводя к голоданию (starvation) других. - Если ни один
case
не готов:- Если есть ветка
default
, выполняется она. - Если ветки
default
нет,select
блокируется до тех пор, пока один изcase
не станет готов.
- Если есть ветка
Пример:
ch1 := make(chan string)
ch2 := make(chan string)
go func() { ch1 <- "from one" }()
go func() { ch2 <- "from two" }()
// Даем горутинам время на запуск
time.Sleep(10 * time.Millisecond)
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
}
В этом примере, если обе горутины успеют отправить данные в свои каналы, select
выберет один из case
случайным образом. При многократном запуске результат будет разным.