select
Тема дорожной карты · Golang
Оператор select в Go — управляющая конструкция, блокирующаяся до тех пор, пока одна из нескольких операций с каналами — отправка или получение — не будет готова, после чего выполняется соответствующая ветка; это основной инструмент мультиплексирования goroutine-коммуникации в Golang-программах. select с веткой default становится неблокирующим, немедленно переходя по default, когда ни один канал не готов, — что полезно для реализации паттернов try-send и try-receive без остановки goroutine. Оператор select — идиоматичный способ реализации таймаутов (case <-time.After(d):), отмены (case <-ctx.Done():), и fan-in с приоритетом из нескольких upstream-каналов — всё это ключевые элементы надёжных конкурентных Golang-бэкендов. Когда одновременно готовы несколько веток, Go-рантайм выбирает одну случайным образом, обеспечивая равномерное распределение, предотвращающее голодание каналов в паттернах worker pool и pipeline. Понимание оператора select в Go необходимо для написания корректного конкурентного кода рядом с goroutines, каналами, sync.WaitGroup и context.Context.
Как это работает
select построен на goroutines (лёгкие green threads, мультиплексируемые на OS-потоки Go-runtime) и channels (типизированные каналы для сообщений между goroutines). go funcName() запускает goroutine; ch <- value шлёт; value := <-ch принимает. select ждёт на нескольких каналах; context.Context несёт cancellation + дедлайны через дерево вызовов. sync.Mutex, sync.WaitGroup, sync.Once, атомарные примитивы, errgroup для группировки goroutines.
Когда применять
Goroutines используйте свободно — дёшевы (~2-4KB stack начально, растёт по нужде). Всегда имейте способ остановить goroutine (cancellation context.Context, close канала, deadline) — утёкшие goroutines = тихий рост памяти. Context первым аргументом — в любую функцию с I/O. sync.Mutex — для shared state, когда channels неудобны. errgroup — для "fan out, wait, первая ошибка пробрасывается".
Типичные ошибки
Ловушки select: утечки goroutines (goroutine ждёт навеки на канале, в который никто не пишет); data race на shared map без mutex (race detector ловит: go test -race); deadlock (go test -race НЕ ловит deadlock — осторожно); не пробрасывают context.Context, и cancellation не доходит до глубокого вызова.