Как каналы устроены в Go
Каналы в Go — это типизированный механизм для синхронизации и обмена данными между горутинами. Они позволяют безопасно передавать значения, избегая гонок данных и сложностей с разделяемой памятью. Канал объявляется с помощью ключевого слова chan и инициализируется функцией make.
Основы работы с каналами
Канал всегда типизирован: он может передавать значения только одного типа. Например, chan int — канал для целых чисел. Создание канала:
ch := make(chan int) // небуферизированный каналОтправка значения в канал выполняется оператором <- слева от канала:
ch <- 10 // отправка числа 10Получение значения — тот же оператор, но справа от канала:
value := <-ch // чтение значения из каналаБлокировки и буферизация
По умолчанию канал небуферизированный. Операции отправки и получения блокирующие:
- Отправка блокирует горутину, пока другая горутина не прочитает значение.
- Получение блокирует горутину, пока другая горутина не отправит значение.
Это обеспечивает синхронизацию: данные передаются только когда обе стороны готовы.
Буферизированный канал создаётся с указанием ёмкости:
ch := make(chan int, 5) // буфер на 5 значенийВ буферизированном канале отправка не блокируется, пока буфер не заполнен, а получение — пока буфер не пуст. Это позволяет отправлять несколько значений без ожидания получателя.
Закрытие каналов
Канал закрывается функцией close(ch). После закрытия отправка в канал вызывает панику. Получение из закрытого канала продолжает работать, пока не будут прочитаны все буферизированные значения; затем получение возвращает нулевое значение типа. Проверить, закрыт ли канал, можно при чтении:
value, ok := <-ch
if !ok {
// канал закрыт и все данные получены
}Закрытие канала — это способ сообщить получателям, что данные закончились. Обычно закрывает отправитель, а не получатель.
Подводные камни
- Отправка в закрытый канал вызывает панику.
- Закрытие закрытого канала тоже вызывает панику.
- Небуферизированный канал без получателя приводит к deadlock'у, если отправитель ждёт.
- Чтение из закрытого канала сразу возвращает нулевое значение, что может быть ошибочно принято за реальные данные, если не использовать
ok.
Когда использовать
Каналы — основной инструмент для коммуникации между горутинами. Их стоит применять для:
- передачи данных между горутинами;
- синхронизации (например, сигнал о завершении работы);
- организации паттернов вроде worker pool или fan-in/fan-out.
Коротко
- Канал — типизированный механизм обмена данными между горутинами.
- Операции отправки и получения блокирующие, если канал небуферизированный.
- Буферизированные каналы позволяют отправлять без немедленного получения.
- Канал закрывается функцией
close, после чего отправка запрещена, а чтение возможно до опустошения буфера. - Проверка закрытия — через
value, ok := <-ch.