我是golang新手,目前正在Exercise: Web Crawler上工作。
我只是在调用func Crawl的每个位置之前都加上了关键字“ go”,并希望它可以并行化,但是fmt.Printf
不起作用并且什么也不打印。除此代码外,原始代码没有其他更改。有人想帮我吗?
func Crawl(url string, depth int, fetcher Fetcher) {
// TODO: Fetch URLs in parallel.
// TODO: Don't fetch the same URL twice.
// This implementation doesn't do either:
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 {
go Crawl(u, depth-1, fetcher)
}
return
}
func main() {
go Crawl("https://golang.org/", 4, fetcher)
}
答案 0 :(得分:3)
根据spec
通过初始化主程序包然后调用函数main开始程序执行。当该函数调用返回时,程序退出。它不等待其他(非主)goroutine完成。
因此,您必须显式等待另一个goroutine以main()
函数结尾。
一种方法是简单地在time.Sleep()
函数的末尾添加main()
,直到您认为另一个goroutine结束(例如,在这种情况下可能为1秒)。
更清洁的方式使用sync.WaitGroup如下:
func Crawl(wg *sync.WaitGroup, url string, depth int, fetcher Fetcher) {
defer wg.Done()
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 {
wg.Add(1)
go Crawl(wg, u, depth-1, fetcher)
}
return
}
func main() {
wg := &sync.WaitGroup{}
wg.Add(1)
// first call does not need to be goroutine since its subroutine is goroutine.
Crawl(wg, "https://golang.org/", 4, fetcher)
//time.Sleep(1000 * time.Millisecond)
wg.Wait()
}
此代码将计数器存储在WaitGroup
中,使用wg.Add()
对其进行递增,使用wg.Done()
进行递减,并使用wg.Wait()
等到其变为零。