我正在经历一次“环游之旅”。并且一直在编辑大部分课程,以确保我完全理解它们。我对以下练习提供的答案有疑问:https://tour.golang.org/concurrency/10可在此处找到:https://github.com/golang/tour/blob/master/solutions/webcrawler.go
我对以下部分有疑问:
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)
在通道done
中添加和删除true以及运行两个单独的for循环有什么用?它只是阻止,直到go例程结束?我知道这是一个示例练习,但这并不是说首先打破了一个新线程的意思吗?
为什么你不能在没有第二个for循环和go Crawl(url, depth-1, fetcher)
频道的情况下拨打done
?是因为所有变量的共享内存空间?
谢谢!
答案 0 :(得分:3)
第一个for
循环计划运行多个goroutine并迭代一段网址。
第二个循环阻塞每个url,等待相应的Crawl()
调用完成。所有Crawl()
个人将并行运行并进行工作,并阻止退出,直到主线程有机会在done
频道上为每个网址收到消息。
在我看来,更好的方法是使用sync.WaitGroup
。除非Crawl()
锁定,否则此代码可能会记录错误的内容,具体取决于每个fetcher
调用的时间。
如果您想确定完成Crawl()
的网址,可以将完成频道的类型更改为string
,然后发送url
代替true
完成Crawl()
后。然后,我们可以在第二个循环中收到url
。
示例:
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)
}