Рекурсивная функция в языке go
Я начал учиться уходить языком несколько дней назад. Когда я попытался начать писать какие-то забавные коды, я застрял в странном поведении.
package main
import "fmt"
func recv(value int) {
if value < 0 {
return
}
fmt.Println(value)
go recv(value-1)
}
func main() {
recv(10)
}
когда я запускаю вышеуказанный код, печатается только 10
. Когда я удаляю go
перед вызовом recv
, отпечатка 10
до 0
. Я считаю, что я злоупотребляю рутиной здесь, но я не могу понять, почему это не удалось запустить рутину таким образом.
Ответы
Ответ 1
Когда возвращается основная функция, Go не будет ждать завершения всех существующих goroutines, но вместо этого просто выйдет.
recv
вернется к главному после первой "итерации", и поскольку main больше нечего делать, программа завершится.
Одним из решений этой проблемы является наличие канала, который сигнализирует, что все работы выполняются следующим образом:
package main
import "fmt"
func recv(value int, ch chan bool) {
if value < 0 {
ch <- true
return
}
fmt.Println(value)
go recv(value - 1, ch)
}
func main() {
ch := make(chan bool)
recv(10, ch)
<-ch
}
Здесь recv
отправит одно логическое значение перед возвратом, а main
будет ждать этого сообщения на канале.
Для логики программы не имеет значения, какой тип или конкретное значение вы используете. bool
и true
- просто простой пример. Если вы хотите быть более эффективным, использование chan struct{}
вместо chan bool
сохранит вам дополнительный байт, поскольку пустые структуры не используют память.
Ответ 2
A sync.Waitgroup
- это еще одно решение и специально предназначено для того, чтобы ждать, пока произвольное количество горутинцев начнет свой курс.
package main
import (
"fmt"
"sync"
)
func recv(value int, wg *sync.WaitGroup) {
if value < 0 {
return
}
fmt.Println(value)
wg.Add(1) // Add 1 goroutine to the waitgroup.
go func() {
recv(value-1, wg)
wg.Done() // This goroutine is finished.
}()
}
func main() {
var wg sync.WaitGroup
recv(10, &wg)
// Block until the waitgroup signals
// all goroutines to be finished.
wg.Wait()
}
Ответ 3
Я сделал это и тоже работал. Почему?
package main
import "fmt"
func recv(value int) {
if value < 0 {
return
}
fmt.Println(value)
recv(value - 1)
}
func main() {
recv(10)
}