为什么Go子程序没有被执行?

huangapple go评论77阅读模式
英文:

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(&quot;Hello from Crawl&quot;)
	if depth &lt;= 0 {
		return
	}
	body, urls, err := fetcher.Fetch(url)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf(&quot;found: %s %q\n&quot;, url, body)
	for _, u := range urls {
		fmt.Println(&quot;in loop with u = %s&quot;, u)
		go Crawl(u, depth-1, fetcher) //I added &quot;go&quot; 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/ &quot;The Go Programming Language&quot;
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(&quot;Hello from Crawl&quot;)
    if depth &lt;= 0 {
        return
    }
    body, urls, err := fetcher.Fetch(url)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf(&quot;found: %s %q\n&quot;, url, body)
   // Adding waiting group to make sure go routines finishes
    wg := sync.WaitGroup{}
    wg.Add(len(urls))
    for _, u := range urls {
        fmt.Println(&quot;in loop with u = %s&quot;, u)
        go func() {
           defer wg.Done()
           Crawl(u, depth-1, fetcher)
        }()
    }
    wg.Wait()
}

huangapple
  • 本文由 发表于 2017年7月3日 16:08:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/44880581.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定