英文:
Why doesn't Go subroutine get executed
问题
我正在学习Go语言,按照在线教程《Go之旅》进行学习。
在这个练习中:https://tour.golang.org/concurrency/10
在解决问题之前,我想尝试一些简单的东西:
func Crawl(url string, depth int, fetcher Fetcher) {
fmt.Println("Hello from Crawl")
if depth <= 0 {
return
}
body, urls, err := fetcher.Fetch(url)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("found: %s %q\n", url, body)
for _, u := range urls {
fmt.Println("in loop with u =", u)
go Crawl(u, depth-1, fetcher) //我在这里添加了"go"命令
}
}
我只是在递归调用Crawl
之前添加了go
命令。我期望这不会对行为产生太大影响。
然而,打印输出结果是:
Hello from Crawl
found: http://golang.org/ "The Go Programming Language"
in loop with u = http://golang.org/pkg/
in loop with u = http://golang.org/cmd/
我期望在循环的每次迭代中都会看到Hello from Crawl
。为什么我的Crawl
子例程没有被执行?
英文:
I'm learning go, following the online tutorial "A tour of Go".
In this excercise: https://tour.golang.org/concurrency/10
Before going on to solve the problem, I wanted to try something simple:
func Crawl(url string, depth int, fetcher Fetcher) {
fmt.Println("Hello from Crawl")
if depth <= 0 {
return
}
body, urls, err := fetcher.Fetch(url)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("found: %s %q\n", url, body)
for _, u := range urls {
fmt.Println("in loop with u = %s", u)
go Crawl(u, depth-1, fetcher) //I added "go" here
}
}
The only thing I added is the go
command right before the recursive call to Crawl
. I expected it should not change much to the behavior.
However the printout is:
Hello from Crawl
found: http://golang.org/ "The Go Programming Language"
in loop with u = http://golang.org/pkg/
in loop with u = http://golang.org/cmd/
I expected to see Hello from Crawl
for each iteration of the loop.
Why doesn't my Crawl
subroutine get executed?
答案1
得分: 2
你的goroutine已经启动,但在完成你想要做的事情之前就结束了,因为你的main()
函数已经结束。与线程类似,goroutine的执行是独立于主程序的,但当程序停止时,它们也会被终止。因此,你需要使用WaitGroup
来等待goroutine完成它们的任务,或者简单地调用time.Sleep()
让主程序休眠一段时间。
英文:
Your goroutines started, but ended before doing what you want to do because your main()
finished. Execution of goroutines is independent of the main program like threads, but will be terminated when program stops. So you need a WaitGroup
to wait for the goroutines to finish their jobs or simply call time.Sleep()
to make the main program sleep for a while.
答案2
得分: 1
确保在程序结束之前,没有任何东西可以确保所有的Go协程都结束,我会将您的代码重构为类似以下的形式:
func Crawl(url string, depth int, fetcher Fetcher) {
fmt.Println("Hello from Crawl")
if depth <= 0 {
return
}
body, urls, err := fetcher.Fetch(url)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("found: %s %q\n", url, body)
// 添加等待组以确保所有的Go协程都结束
wg := sync.WaitGroup{}
wg.Add(len(urls))
for _, u := range urls {
fmt.Println("in loop with u =", u)
go func(u string) {
defer wg.Done()
Crawl(u, depth-1, fetcher)
}(u)
}
wg.Wait()
}
请注意,我将匿名函数中的参数u
传递给了go
语句,以确保每个协程都使用正确的URL进行递归调用。
英文:
There is nothing to make sure that all your go routines ends before your program finishes, I'd refactor your code to something similar to this:
func Crawl(url string, depth int, fetcher Fetcher) {
fmt.Println("Hello from Crawl")
if depth <= 0 {
return
}
body, urls, err := fetcher.Fetch(url)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("found: %s %q\n", url, body)
// Adding waiting group to make sure go routines finishes
wg := sync.WaitGroup{}
wg.Add(len(urls))
for _, u := range urls {
fmt.Println("in loop with u = %s", u)
go func() {
defer wg.Done()
Crawl(u, depth-1, fetcher)
}()
}
wg.Wait()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论