Являются ли операции с каналами в Go блокирующими
Что проверяют
Знаете ли вы поведение в каждом случае и понимаете ли, что блокируется горутина, а не поток.
Как отвечать
Да, по умолчанию блокирующие, но детали зависят от вида канала и состояния.
Небуферизованный канал: отправка блокируется до появления получателя, получение до появления отправителя. Это точка встречи двух горутин, и передача происходит одновременно для обеих сторон.
Буферизованный канал: отправка не блокирует, пока в буфере есть место, и блокируется при его заполнении. Получение не блокирует, пока в буфере есть данные, и блокируется на пустом.
Закрытый канал ведёт себя иначе: получение из него не блокирует никогда и сразу возвращает нулевое значение с признаком закрытия. А вот отправка в закрытый канал вызывает панику.
Нулевой канал блокирует навсегда в обе стороны. Это не ошибка, а полезное свойство: обнулив переменную канала внутри конструкции выбора, вы исключаете эту ветку из рассмотрения.
Ключевое уточнение, которое отличает понимающего: блокируется горутина, а не поток операционной системы. Планировщик снимает её с потока и переводит в ожидание, а поток берёт другую работу. Стоимость такой блокировки близка к нулю, поэтому блокирующих операций в Go не боятся, в отличие от языков, где ожидание занимает настоящий поток.
Как сделать операцию неблокирующей: конструкция выбора с веткой по умолчанию. Она выполняется, если ни один канал не готов немедленно.
select {
case ch <- value:
// отправили
default:
// канал занят, идём дальше
}Туда же добавляют ветку отмены по контексту или таймаут, и это правильный способ не зависнуть навсегда.
Главная опасность блокировки: если противоположной стороны не появится никогда, горутина зависает насовсем. Это утечка, и рантайм сообщит о ней только если заблокированы абсолютно все горутины программы.
Где спотыкаются
Считают, что заблокированная горутина занимает поток.
Не знают, что закрытый канал всегда готов к чтению, и получают холостой цикл.
Не добавляют выход по контексту и получают утечку горутин.
Ждут, что рантайм всегда обнаружит зависание.