Является ли select блокирующей конструкцией в Go
Что проверяют
Понимаете ли вы семантику select, а не заучили формулу «это switch для каналов». Вопрос с подвохом: правильный ответ зависит от того, есть ли ветка default, и именно эту оговорку хотят услышать.
Как отвечать
Без default конструкция блокирующая: горутина стоит, пока хотя бы одна из перечисленных операций, приём или отправка, не сможет выполниться. С default она не блокируется никогда, потому что при неготовности всех веток немедленно выполняется default.
Дальше детали, ради которых вопрос и задают.
При нескольких готовых ветках выбор случайный и равновероятный, приоритета по порядку записи нет.
Операция на нулевом канале не готова никогда, поэтому обнуление переменной канала это штатный способ выключить ветку в цикле.
Закрытый канал, наоборот, готов всегда и мгновенно отдаёт нулевое значение, что в цикле превращается в холостое кручение, если не обнулить канал и не выйти.
Пустой select без веток блокирует горутину навсегда.
select {
case v := <-in:
handle(v)
case <-ctx.Done():
return ctx.Err()
default:
// очередь пуста, ждать не нужно
}Типовые применения: таймаут, отмена по контексту, неблокирующая отправка в буферизованный канал, чтобы отправка метрики не тормозила основной поток работы.
Где спотыкаются
Считают, что ветки проверяются сверху вниз, и ставят важную первой. Приоритета нет; чтобы его получить, делают вложенную конструкцию: сначала проверяют приоритетный канал с веткой default, и только потом уходят в общее ожидание.
Добавляют default внутрь цикла, чтобы не блокироваться, и получают цикл, который впустую жжёт процессор. Ждать нужно на каналах, опрос в цикле здесь почти всегда ошибка.
Кладут таймер time.After прямо в цикл. Он создаётся заново на каждой итерации и живёт до срабатывания, поэтому под нагрузкой копится мусор; для повторяющегося ожидания берут time.NewTimer с Stop и Reset или контекст с дедлайном.