← Назад к вопросам

Что произойдет, если писать, но не вычитывать из небуферизированного канала?

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
}

Почему происходит блокировка?

Небуферизированный канал требует синхронизации между отправителем и получателем:

  1. Отправитель блокируется, пока получатель не прочитает значение
  2. Получатель блокируется, пока отправитель не напишет значение
  3. Это гарантирует, что значение не теряется и не дублируется

Последствия: 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, чтобы избежать вечной блокировки
  • При проектировании убедитесь, что все горутины могут разблокироваться