Ответ
Последствия зависят от типа канала: небуферизованный или буферизованный.
1. Небуферизованный канал (make(chan int)
)
Отправка в такой канал является синхронной операцией. Это означает, что горутина-отправитель будет немедленно заблокирована до тех пор, пока другая горутина не будет готова прочитать данные из этого канала.
- Последствие: Если никто никогда не прочитает данные, горутина-отправитель останется заблокированной навсегда. Это называется утечкой горутины (goroutine leak) и может привести к deadlock, если основная программа ждет завершения этой горутины.
// Эта горутина заблокируется навсегда, так как никто не читает из ch.
func main() {
ch := make(chan int)
go func() {
ch <- 42 // Блокировка здесь
}()
// Программа "зависнет" или завершится с deadlock, если все горутины спят
select{}
}
2. Буферизованный канал (make(chan int, N)
)
Отправка в такой канал является асинхронной, пока в буфере есть свободное место.
Горутина-отправитель может успешно отправить
N
значений в канал без блокировки.При попытке отправить
N+1
-ое значение, когда буфер полон, горутина-отправитель будет заблокирована — точно так же, как и в случае с небуферизованным каналом.Последствие: Если буфер заполнится и никто не будет читать из канала, горутина-отправитель также будет заблокирована навсегда, что приведет к утечке горутины и возможному deadlock.
ch := make(chan int, 1) // Буфер размером 1
ch <- 1 // OK, не блокирует
ch <- 2 // Блокировка! Буфер полон, и никто не читает.
Как избежать проблем:
- Управляйте жизненным циклом: Убедитесь, что для каждой горутины-отправителя есть горутина-получатель, или что у горутины есть способ завершиться, даже если отправка блокируется (например, через
context
илиselect
с таймаутом). - Закрывайте каналы: Когда отправитель закончил посылать данные, он должен закрыть канал с помощью
close(ch)
. Это сигнализирует получателям, что данных больше не будет. - Используйте
select
сdefault
: Для неблокирующей отправки можно использовать конструкциюselect
:
select {
case ch <- data:
// Данные успешно отправлены
default:
// Канал заблокирован, выполняем альтернативное действие
}