来自Go'巡回赛的频道说明Webcrawler练习

时间:2017-09-11 03:49:17

标签: go

我正在经历一次“环游之旅”。并且一直在编辑大部分课程,以确保我完全理解它们。我对以下练习提供的答案有疑问: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?是因为所有变量的共享内存空间?

谢谢!

1 个答案:

答案 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)
}