Почему программа уходит в deadlock, когда горутина проходит range по channel, который никогда не закрывают?
Горутина-потребитель проходит range по ch, пока main отправляет два значения и ждёт на WaitGroup. Программа уходит в deadlock вместо завершения.
func main() {
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for v := range ch {
fmt.Println(v)
}
}()
ch <- 1
ch <- 2
wg.Wait()
}
Найдите ошибку и объясните причину.
for v := range ch принимает значения, пока channel не закрыт. Продьюсер отправляет 1 и 2, но никогда не вызывает close(ch), поэтому потребитель навсегда блокируется после их вычерпывания, wg.Done() не выполняется, и wg.Wait() тоже блокируется — deadlock. Исправление: close(ch) после последней отправки.
- ✗Думать, что
range chостанавливается, когда channel пуст, а не когда он закрыт - ✗Закрывать channel из получателя вместо отправителя
- ✗Забывать, что незакрытый channel держит горутину
rangeживой, поэтомуwg.Wait()не возвращается
- →Кто отвечает за закрытие channel и почему никогда не получатель?
- →Как
selectс каналомdoneпозволил бы потребителю выйти без закрытия?
Найдите ошибку
func main() {
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for v := range ch { // блокируется навсегда, ожидая close
fmt.Println(v)
}
}()
ch <- 1
ch <- 2
wg.Wait()
}
Почему deadlock
for v := range ch — это цикл приёма, который завершается только когда channel закрыт. Пока канал открыт, после вычерпывания всех значений range блокируется в ожидании следующего.
Продьюсер отправляет 1 и 2, потребитель их печатает — а затем range повисает, ожидая ещё значений или close. Поскольку close(ch) никогда не вызывается:
- горутина-потребитель навсегда стоит в
range; defer wg.Done()не выполняется;wg.Wait()вmainждёт счётчик, который не дойдёт до нуля.
Все горутины спят → deadlock!.
✅ Исправление — закрыть channel после последней отправки (закрывает отправитель):
ch <- 1
ch <- 2
close(ch) // range завершится, wg.Done выполнится
wg.Wait()