Писали ли вы собственные реализации каналов в Go или использовали готовые
Что проверяют
Понимаете ли вы, что канал это примитив самого языка, а не библиотечная структура, и слышите ли в вопросе подвох. Заодно проверяют, знаете ли вы, чем решаются задачи, ради которых кто-то захотел бы свой канал: ограничение нагрузки, приоритеты, буфер с вытеснением.
Как отвечать
Скажите прямо: каналы реализованы в рантайме, переписывать их незачем. Своими руками пишут не канал, а обёртки и шаблоны поверх него:
- пул обработчиков: несколько горутин читают из одного канала задач, результаты уходят в другой;
- ограничение параллелизма через буферизованный канал как счётчик разрешений;
- слияние нескольких источников в один канал и обратное разветвление;
- очередь с вытеснением старых элементов, для которой берут
selectс веткойdefaultлибо кольцевой буфер наsync.Mutexиsync.Cond.
Покажите знание правил, на которых всё держится: закрывает канал только пишущая сторона, чтение из закрытого канала отдаёт нулевое значение и false, отправка в закрытый канал это паника, а операции с нулевым каналом блокируются навсегда. Отмена делается не своим механизмом, а через context и ветку case <-ctx.Done() в select.
Полезно добавить, когда канал не нужен вовсе: для защиты одного счётчика или карты проще sync.Mutex либо атомарные операции, канал тут добавит только лишних переключений горутин.
Где спотыкаются
Говорят, что писали свой канал, и не могут объяснить, чем он лучше встроенного. Обычно под этим скрывается обёртка над обычным каналом, так её и стоит называть, иначе разговор уходит в разбор несуществующего опыта.
Второе: закрывают канал со стороны читателя или закрывают дважды. И то и другое кончается паникой, а при нескольких писателях закрытие координируют через sync.WaitGroup и закрывают уже после ожидания.
Третье: забывают про утечку горутин. Горутина, зависшая на отправке в канал, который больше никто не читает, живёт до конца процесса, и такие утечки заметны только по росту их числа под нагрузкой.