В первом варианте кода есть проблема: цикл for r := range c будет бесконечно ждать, потому что канал c никогда не закрывается. Из-за этого программа зависнет.
func main() {
В первом варианте кода есть проблема: цикл for r := range c будет бесконечно ждать, потому что канал c никогда не закрывается. Из-за этого программа зависнет.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
func main() { c := make(chan int, 1000) for i := 0; i < 100; i++ { go foo(c) }
sum := 0
for r := range c {
sum += r
}
fmt.Println(sum)
}
func foo(c chan int) { r := rand.Int() for i := 0; i < r; i++ { c <- r } }
func main() { c := make(chan int, 1000) var wg sync.WaitGroup
wg.Add(100)
for i := 0; i < 100; i++ {
go func() {
defer wg.Done()
foo(c)
}()
}
go func() {
wg.Wait()
close(c)
}()
sum := 0
for r := range c {
sum += r
}
//
// fmt.Println(sum)
}
func foo(c chan int) { r := rand.Int() for i := 0; i < r; i++ { c <- r } }
Ответ
В первом варианте кода есть проблема: цикл for r := range c будет бесконечно ждать, потому что канал c никогда не закрывается. Из-за этого программа зависнет.
Во втором варианте добавлен sync.WaitGroup для ожидания завершения всех горутин, и после этого канал c закрывается. Это позволяет корректно выйти из цикла чтения из канала.
Ключевые моменты:
- Использование
sync.WaitGroupдля отслеживания завершения всех горутин. - Закрытие канала после того, как все горутины закончат запись.
- Итерация по каналу с помощью
for r := range cзавершается, когда канал закрыт.
Пример исправленного кода:
group := sync.WaitGroup{}
group.Add(100)
for i := 0; i < 100; i++ {
go func() {
defer group.Done()
foo(c)
}()
}
go func() {
group.Wait()
close(c)
}()
sum := 0
for r := range c {
sum += r
}