我对以下部分有疑问:
done := make(chan bool) for i, u := range urls { fmt.Printf("-> Crawling child %v/%v of %v : %v.\n", i, len(urls), url, u) go func(url string) { Crawl(url, depth-1, fetcher) done <- true }(u) } for i, u := range urls { fmt.Printf("<- [%v] %v/%v Waiting for child %v.\n", url, i, len(urls), u) <-done } fmt.Printf("<- Done with %v\n", url)
从通道添加和删除true done并运行两个单独的for循环有什么目的?它只是阻塞直到go例程完成?我知道这是一个示例练习,但是这种做法是否首先克服了新线程的不足?
done
为什么go Crawl(url, depth-1, fetcher)没有第二个for循环和done通道就不能打电话?是否因为所有变量共享存储空间?
go Crawl(url, depth-1, fetcher)
谢谢!
第一个for循环调度了多个goroutine来运行,并且正在一片URL上进行迭代。
for
第二个循环在每个url上阻塞,等待其相应的Crawl()调用完成。所有用户Crawl()将并行运行并执行其工作,并阻止退出,直到主线程有机会在done通道上收到每个URL 的消息。
Crawl()
我认为,实现此效果的更好方法是使用sync.WaitGroup。此代码可能会记录错误的内容,具体取决于每次Crawl()调用要花费多长时间(除非fetcher锁定)。
sync.WaitGroup
fetcher
如果你想确保网址的是成品Crawl()ING,你可以改变做过通道的类型string并发送url,而不是true一个后Crawl()完成。然后,我们可以url在第二个循环中接收。
string
url
true
例:
done := make(chan string) for _, u := range urls { fmt.Printf("-> Crawling %s\n", u) go func(url string) { Crawl(url, depth-1, fetcher) done <- url }(u) } for range urls { fmt.Printf("<- Waiting for next child\n") u := <-done fmt.Printf(" Done... %s\n", u) }