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

Что будет, если попытатся писать в закрытом канале

Запись в закрытый канал в Go вызывает панику (panic). Это одно из фундаментальных отличий от чтения из закрытого канала, которое безопасно и возвращает нулевое значение. Паника возникает на этапе выполнения программы и, если её не перехватить, приведёт к аварийному завершению работы приложения.

Как это работает

Каналы в Go — это типизированный механизм передачи данных между горутинами. Закрытие канала сигнализирует о том, что отправка данных в него больше не ожидается. При попытке записи в закрытый канал runtime обнаруживает это нарушение и инициирует панику. Это поведение заложено в спецификации языка и не зависит от того, есть ли буфер у канала или нет.

Пример кода, демонстрирующий панику:

go
package main

func main() {
    ch := make(chan int)
    close(ch)
    ch <- 42 // Паника: send on closed channel
}

При выполнении этой программы будет выведено сообщение об ошибке и стек вызовов, после чего программа завершится с ненулевым кодом возврата.

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

Паника при записи в закрытый канал — это не единственный сценарий, который стоит учитывать. Вот несколько важных моментов:

  • Чтение из закрытого канала — безопасно. Читатель получит нулевое значение типа канала и флаг ok равный false, если используется форма с двумя возвращаемыми значениями.
  • Закрытие закрытого канала — также вызывает панику. Повторное закрытие канала запрещено.
  • Запись в канал, который не был закрыт, но из него никто не читает — может привести к блокировке горутины, если канал небуферизованный или буфер заполнен. Это не паника, но может вызвать взаимоблокировку (deadlock).
  • Панику можно перехватить с помощью recover в отложенной функции (defer), но это не должно быть стандартной практикой для обработки ошибок.

Как избежать паники

Чтобы не столкнуться с паникой при записи в закрытый канал, следуйте этим рекомендациям:

  • Закрывайте канал только в горутине-отправителе, когда уверены, что больше не будет отправок.
  • Используйте паттерн sync.Once для гарантии однократного закрытия канала, если несколько горутин могут попытаться его закрыть.
  • Проверяйте состояние канала перед записью, если это возможно, хотя в конкурентной среде такая проверка не всегда надёжна.
  • Рассмотрите использование select с default для неблокирующей отправки, но это не защитит от паники, если канал уже закрыт.

Коротко

  • Запись в закрытый канал вызывает панику, которая приводит к аварийному завершению программы, если её не перехватить.
  • Чтение из закрытого канала безопасно и возвращает нулевое значение.
  • Закрытие уже закрытого канала также вызывает панику.
  • Для безопасной работы с каналами закрывайте их только в отправителе и используйте sync.Once при необходимости.
как отвечать на вопрос
пример собеседования
фреймворки на собеседовании
типичные вопросы junior
интервью вопросы и ответы