我刚开始学习go,并且一直在参加巡演。最后一个练习是编辑Web爬网程序以并行爬行而不重复。
以下是练习的链接:http://tour.golang.org/#70
这是代码。我只改变了爬行和主要功能。所以我会发布那些以保持整洁。
// Crawl uses fetcher to recursively crawl
// pages starting with url, to a maximum of depth.
var used = make(map[string]bool)
var urlchan = make(chan string)
func Crawl(url string, depth int, fetcher Fetcher) {
// TODO: Fetch URLs in parallel.
// Done: Don't fetch the same URL twice.
// This implementation doesn't do either:
done := make(chan bool)
if depth <= 0 {
return
}
body, urls, err := fetcher.Fetch(url)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("\nfound: %s %q\n\n", url, body)
go func() {
for _, i := range urls {
urlchan <- i
}
done <- true
}()
for u := range urlchan {
if used[u] == false {
used[u] = true
go Crawl(u, depth-1, fetcher)
}
if <-done == true {
break
}
}
return
}
func main() {
used["http://golang.org/"] = true
Crawl("http://golang.org/", 4, fetcher)
}
问题是当我运行程序时,爬行程序在打印后停止
not found: http://golang.org/cmd/
仅当我尝试使程序并行运行时才会发生这种情况。如果我让它线性运行,那么所有网址都会被正确找到。
注意:如果我没有这样做(我的意思是并行性),那么我道歉。
答案 0 :(得分:1)
main()
func返回时,所有其他常规程序将立即被杀死。 Crawl()
似乎是递归的,但它不是,这意味着它会立即返回,而不是等待其他Crawl()
例程。而且你知道,如果由Crawl()
调用的第一个main()
返回,则main()
func会将其任务完成。 main()
func等到最后Crawl()
返回。 sync
包或chan
会有所帮助。您可以查看this的最后一个解决方案,这是我几个月前做的:
var store map[string]bool
func Krawl(url string, fetcher Fetcher, Urls chan []string) {
body, urls, err := fetcher.Fetch(url)
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("found: %s %q\n", url, body)
}
Urls <- urls
}
func Crawl(url string, depth int, fetcher Fetcher) {
Urls := make(chan []string)
go Krawl(url, fetcher, Urls)
band := 1
store[url] = true // init for level 0 done
for i := 0; i < depth; i++ {
for band > 0 {
band--
next := <- Urls
for _, url := range next {
if _, done := store[url] ; !done {
store[url] = true
band++
go Krawl(url, fetcher, Urls)
}
}
}
}
return
}
func main() {
store = make(map[string]bool)
Crawl("http://golang.org/", 4, fetcher)
}