Как оператор `select` выбирает, какой case выполнить?

Ответ

В операторе select нет предопределенного приоритета. Выбор case для выполнения подчиняется следующим правилам:

  1. Если готовы несколько case (т.е. коммуникация по нескольким каналам возможна), select выбирает один из них псевдослучайным образом. Это сделано для предотвращения "голодания" (starvation) одного из каналов, когда другой всегда готов.

    ch1 := make(chan int, 1)
    ch2 := make(chan int, 1)
    
    ch1 <- 1
    ch2 <- 2
    
    // Оба канала готовы к чтению
    select {
    case v := <-ch1:
        fmt.Println("Получено из ch1:", v)
    case v := <-ch2:
        fmt.Println("Получено из ch2:", v)
    }
    // При каждом запуске результат может быть разным
  2. Если ни один case не готов, поведение зависит от наличия ветки default:

    • Если есть default, выполняется он, и select не блокируется.
    • Если default отсутствует, select блокирует текущую горутину до тех пор, пока один из case не станет готов к выполнению.
  3. Если select не содержит ни одного case (например, select {}), он блокируется навсегда. Это может быть полезно для блокировки основной горутины в конце программы, чтобы другие горутины успели завершить работу.