我正在经历 Go Tour,我觉得除了并发之外,我对这门语言有了很好的理解。
slide 10 https://tour.golang.org/concurrency/10是一个要求读者并行化网络爬虫的练习(并使其不覆盖重复,但我还没有做到这一点。)
这是我到目前为止所拥有的:
func Crawl(url string, depth int, fetcher Fetcher, ch chan string) {
if depth <= 0 {
return
}
body, urls, err := fetcher.Fetch(url)
if err != nil {
ch <- fmt.Sprintln(err)
return
}
ch <- fmt.Sprintf("found: %s %q\n", url, body)
for _, u := range urls {
go Crawl(u, depth-1, fetcher, ch)
}
}
func main() {
ch := make(chan string, 100)
go Crawl("http://golang.org/", 4, fetcher, ch)
for i := range ch {
fmt.Println(i)
}
}
我的问题是,我该把close(ch)
call.
如果我放一个defer close(ch)
某处在Crawl
方法,那么程序最终会从生成的 goroutine 之一写入关闭的通道,因为调用Crawl
将在生成的 goroutine 之前返回。
如果我省略调用close(ch)
正如我所演示的,程序在主函数范围内死锁,因为当所有 goroutine 返回时通道永远不会关闭。