Конкуренция в Go
Теория: Select
select в Go — это инструмент управления конкурентными событиями. Он позволяет горутине ждать сразу несколько операций на каналах и реагировать на ту, которая сработала первой. Это делает код отзывчивым и управляемым: программа не блокируется на одном канале и может реагировать на таймауты, сигналы отмены или внешние события.
Синтаксис select
select по структуре похож на switch, но работает с каналами. Каждая ветка — это операция чтения или записи. Как только одна из них становится готовой, выполняется соответствующий блок.
Если обе ветки готовы одновременно, планировщик выбирает случайную. Это гарантирует равномерную нагрузку и отсутствие приоритета. Если ни один канал не готов, select блокирует горутину до появления данных.
Ожидание на нескольких каналах
Основное применение — слушать сразу несколько источников. Например, одна горутина пишет логи, а другая может прислать команду остановки:
Здесь select ждет данные из data, но одновременно следит за сигналом quit. Если данные кончились или поступил сигнал, цикл завершается.
Ветка default в select
Иногда нужно проверить состояние каналов, не блокируясь. Для этого есть ветка default. Она выполняется, если ни один канал не готов. Это удобно для опроса или периодических проверок:
Такой select не ждет — если канал пуст, выполняется default. Этот прием часто применяют в неблокирующих очередях или циклах событий.
Таймауты с time.After
В реальных программах ожидание не может длиться бесконечно. Чтобы ограничить время, Go предоставляет time.After(d). Эта функция возвращает канал, который сработает через заданное время. В select он становится простым средством задания таймаута.
Если ответ не придет за две секунды, выполнится вторая ветка, и программа продолжит работу. Это надежный способ защититься от зависаний при сетевых запросах или ожидании сигналов.
Прерывание ожидания через context
Контекст (context.Context) — это стандартный способ управлять временем жизни операций. Его канал Done() срабатывает, когда контекст отменяется или истекает срок действия. Его удобно добавлять в select, чтобы в любой момент можно было остановить ожидание.
Контекст завершится раньше, чем придет сообщение, и ветка ctx.Done() выполнится первой. Этот механизм используется повсеместно — от HTTP-запросов до баз данных, где важно уметь корректно прервать операцию.
select превращает конкурентные программы в управляемые системы событий. Он объединяет каналы, таймеры и контексты в одну простую конструкцию. Вместо бесконечных циклов и флагов программа просто ждет: «что готово — то и выполняем». Благодаря этому Go остается минималистичным языком, но при этом способен решать задачи любой сложности в области асинхронного и параллельного программирования.


