Почему нельзя заменить канал в Go обычным слайсом сообщений?
Что проверяют
Понимаете ли вы, что канал это не потокобезопасный список, а механизм синхронизации. Ответ уровня «слайс не потокобезопасен» засчитают как минимум, дальше ждут блокировку получателя и гарантии видимости памяти.
Как отвечать
Начните с очевидного: слайс это указатель, длина и ёмкость. Два конкурентных append дают гонку данных, причём теряется не только элемент: при перевыделении массива запись уйдёт в старую память.
Главное дальше. Даже слайс под мьютексом не решает задачу передачи. Получателю нечего ждать, он вынужден крутиться в цикле и опрашивать длину, то есть жечь процессор или спать наугад. Канал паркует горутину, планировщик снимает её с потока и будит ровно в момент отправки.
Что ещё даёт канал и чего нет у очереди на слайсе:
selectнад несколькими источниками вместе сctx.Done(), то есть отмена без отдельного флага;- буфер как ограничение нагрузки: отправитель притормаживает, когда получатель не успевает;
- завершение через
closeи обходfor range, при котором об окончании узнают все получатели; - гарантия порядка памяти: отправка в канал происходит раньше завершения приёма, поэтому данные, записанные до отправки, видны принимающей горутине.
Оговорите и обратное: канал это очередь без приоритетов и без заглядывания внутрь. Если нужно разделяемое состояние с произвольным доступом, слайс или карта под мьютексом уместнее, и это тоже идиоматичный Go.
Где спотыкаются
Сводят ответ к потокобезопасности. Мьютекс тоже даёт безопасность, но не даёт ни ожидания, ни отмены, ни гарантии видимости, а именно за ними канал и берут.
Забывают про завершение работы. Получатель на канале, который никто не закрыл, висит вечно, и это утечка горутины, закрывать канал должен отправитель, а запись в закрытый канал завершается паникой.
Уверены, что канал быстрее. На частом обмене мелкими сообщениями он ощутимо дороже мьютекса или атомарной операции, и выбирают его за понятное владение данными и за select, а не за скорость.