Встречается на 91% собеседований по Go

Как каналы устроены в Go

Каналы в Go — это типизированный механизм для синхронизации и обмена данными между горутинами. Они позволяют безопасно передавать значения, избегая гонок данных и сложностей с разделяемой памятью. Канал объявляется с помощью ключевого слова chan и инициализируется функцией make.

Основы работы с каналами

Канал всегда типизирован: он может передавать значения только одного типа. Например, chan int — канал для целых чисел. Создание канала:

go
ch := make(chan int) // небуферизированный канал

Отправка значения в канал выполняется оператором <- слева от канала:

go
ch <- 10 // отправка числа 10

Получение значения — тот же оператор, но справа от канала:

go
value := <-ch // чтение значения из канала

Блокировки и буферизация

По умолчанию канал небуферизированный. Операции отправки и получения блокирующие:

  • Отправка блокирует горутину, пока другая горутина не прочитает значение.
  • Получение блокирует горутину, пока другая горутина не отправит значение.

Это обеспечивает синхронизацию: данные передаются только когда обе стороны готовы.

Буферизированный канал создаётся с указанием ёмкости:

go
ch := make(chan int, 5) // буфер на 5 значений

В буферизированном канале отправка не блокируется, пока буфер не заполнен, а получение — пока буфер не пуст. Это позволяет отправлять несколько значений без ожидания получателя.

Закрытие каналов

Канал закрывается функцией close(ch). После закрытия отправка в канал вызывает панику. Получение из закрытого канала продолжает работать, пока не будут прочитаны все буферизированные значения; затем получение возвращает нулевое значение типа. Проверить, закрыт ли канал, можно при чтении:

go
value, ok := <-ch
if !ok {
    // канал закрыт и все данные получены
}

Закрытие канала — это способ сообщить получателям, что данные закончились. Обычно закрывает отправитель, а не получатель.

Подводные камни

  • Отправка в закрытый канал вызывает панику.
  • Закрытие закрытого канала тоже вызывает панику.
  • Небуферизированный канал без получателя приводит к deadlock'у, если отправитель ждёт.
  • Чтение из закрытого канала сразу возвращает нулевое значение, что может быть ошибочно принято за реальные данные, если не использовать ok.

Когда использовать

Каналы — основной инструмент для коммуникации между горутинами. Их стоит применять для:

  • передачи данных между горутинами;
  • синхронизации (например, сигнал о завершении работы);
  • организации паттернов вроде worker pool или fan-in/fan-out.

Коротко

  • Канал — типизированный механизм обмена данными между горутинами.
  • Операции отправки и получения блокирующие, если канал небуферизированный.
  • Буферизированные каналы позволяют отправлять без немедленного получения.
  • Канал закрывается функцией close, после чего отправка запрещена, а чтение возможно до опустошения буфера.
  • Проверка закрытия — через value, ok := <-ch.
как отвечать на вопрос
пример собеседования
фреймворки на собеседовании
типичные вопросы junior
интервью вопросы и ответы