Ответ
Каналы — это фундаментальный инструмент в Go для безопасной коммуникации и синхронизации между горутинами. Они позволяют избежать состояния гонки при доступе к общим данным.
Типы каналов:
- Небуферизированные (
make(chan T)
): Обеспечивают синхронизацию. Отправка в такой канал блокируется до тех пор, пока другая горутина не будет готова принять данные, и наоборот. Это как "точка рандеву". - Буферизированные (
make(chan T, N)
): Работают как небольшая очередь FIFO. Отправка блокируется только когда буфер полон, а чтение — когда он пуст. Это позволяет развязать (decouple) отправителя и получателя.
Паттерны и сценарии использования:
-
Worker Pool (Пул воркеров) Классический паттерн для параллельной обработки задач. Одна горутина (продюсер) отправляет задачи в канал, а несколько горутин-воркеров читают из него и выполняют работу.
jobs := make(chan int, 100) results := make(chan int, 100) // Запускаем воркеров for w := 1; w <= 3; w++ { go worker(w, jobs, results) } // Отправляем задачи for j := 1; j <= 5; j++ { jobs <- j } close(jobs)
-
Fan-out / Fan-in
- Fan-out: Одна горутина распределяет задачи по нескольким каналам или воркерам.
- Fan-in: Несколько горутин-продюсеров пишут в один общий канал, который агрегирует результаты.
-
Мультиплексирование с
select
Операторselect
позволяет горутине ждать данные сразу из нескольких каналов.- Обработка нескольких источников:
case data := <-ch1: ... case data := <-ch2: ...
- Таймауты:
case <-time.After(1 * time.Second): // таймаут
- Неблокирующие операции:
default: // выполнить, если ни один канал не готов
- Обработка нескольких источников:
-
Сигнализация о завершении Использование пустого канала
chan struct{}
для отправки сигналов без передачи данных. Например, для graceful shutdown.
Частые ошибки:
- Deadlock: Все горутины заблокированы в ожидании друг друга. Часто случается при отправке в небуферизированный канал без активного получателя.
- Panic: Отправка данных в уже закрытый канал вызывает панику.
- Утечка горутин: Горутина блокируется на чтении или записи в канал, из/в который никто никогда не будет писать/читать.