Ответ вслух Senior Каналы и select обновлено

Приоритет в select

Вопрос

Нужно обрабатывать сообщения из двух каналов, но управляющие команды из ctrl должны всегда обрабатываться раньше данных из data. Как это сделать, если select выбирает случайно?

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

Встроенного приоритета нет: если готовы обе ветки, select выберет любую с вероятностью 1/2. Поэтому делаю два этапа в цикле.

Что должно прозвучать в ответе

  • select не даёт приоритета: при двух готовых ветках выбор равновероятен

  • Сначала неблокирующий select только по ctrl с default

  • Затем общий select по обоим каналам

  • Альтернатива: вложенный select внутри ветки data, проверяющий ctrl

  • Учесть закрытие каналов (nil для выключенной ветки) и отмену по ctx

Что могут спросить следом

  • Гарантирует ли такой подход, что ни одна команда не обработается после данных, пришедших позже?
  • Как избежать голодания data при потоке команд?

Разбор

Встроенного приоритета нет: если готовы обе ветки, select выберет любую с вероятностью 1/2. Поэтому делаю два этапа в цикле. Первый: неблокирующий select только по ctrl с default: если команда есть, обрабатываю и иду на следующую итерацию. Второй: обычный блокирующий select по ctrl, data и ctx.Done(). Если в нём выбралась data, а в этот же момент пришла команда, это нормально: команда пришла одновременно, и строгого порядка между независимыми каналами всё равно нет. Закрытые каналы выключаю присвоением nil, выход по ctx. Если поток команд бесконечный, data может голодать, тогда ограничиваю число команд подряд. Иногда проще слить всё в один канал с типом сообщения и приоритетной очередью внутри одной горутины.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.