← Назад к вопросам
Что произойдет, если писать, но не вычитывать из небуферизированного канала?
1.0 Junior🔥 251 комментариев
#Конкурентность и горутины#Основы Go
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что произойдет при записи в небуферизированный канал без чтения
Основной результат: горутина заблокируется
Если вы пытаетесь писать в небуферизированный канал (создан без буфера), но никто не читает из этого канала, горутина, пытающаяся писать, блокируется на неопределённое время в ожидании горутины-читателя.
package main
import "fmt"
func main() {
// Создаём небуферизированный канал
ch := make(chan int)
// Запускаем горутину, которая пытается написать
go func() {
fmt.Println("Горутина: пытаюсь писать...")
ch <- 42 // БЛОКИРОВКА! Никто не читает
fmt.Println("Это никогда не выполнится")
}()
// Главная горутина никогда не читает из канала
// Программа зависнет в deadlock
}
Почему происходит блокировка?
Небуферизированный канал требует синхронизации между отправителем и получателем:
- Отправитель блокируется, пока получатель не прочитает значение
- Получатель блокируется, пока отправитель не напишет значение
- Это гарантирует, что значение не теряется и не дублируется
Последствия: Deadlock
При невозможности разблокировки программа зависает с ошибкой:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
Эта ошибка означает, что все горутины ждут друг друга в бесконечном цикле блокировок.
Правильный пример
package main
import "fmt"
func main() {
ch := make(chan int)
// Горутина-отправитель
go func() {
fmt.Println("Отправляю значение...")
ch <- 42
fmt.Println("Значение отправлено")
}()
// Горутина-получатель (в главной функции)
value := <-ch // БЛОКИРОВКА до тех пор, пока не придёт значение
fmt.Println("Получено:", value)
// Вывод: Получено: 42
}
Решение проблемы: буферизированный канал
Если нужно, чтобы отправитель не блокировался, используйте буферизированный канал:
ch := make(chan int, 1) // Буфер на 1 элемент
go func() {
ch <- 42 // Не блокируется, т.к. есть место в буфере
fmt.Println("Записано без блокировки")
}()
time.Sleep(time.Second)
value := <-ch
fmt.Println("Получено:", value)
Альтернатива: select с timeout
ch := make(chan int)
select {
case ch <- 42:
fmt.Println("Успешно отправлено")
case <-time.After(2 * time.Second):
fmt.Println("Timeout: не удалось отправить")
}
Ключевые выводы
- Небуферизированные каналы требуют синхронизации отправителя и получателя
- Запись без читателя приводит к горутине-зомби и deadlock
- Используйте буферизированные каналы, если отправитель не должен блокироваться
- Используйте select с timeout, чтобы избежать вечной блокировки
- При проектировании убедитесь, что все горутины могут разблокироваться