我正在经历golang之旅,并在最后一个练习中进行工作,以将网络爬虫更改为并行爬网,而不是重复爬网(http://tour.golang.org/#73)。我所更改的只是爬网功能。

    var used = make(map[string]bool)

    func Crawl(url string, depth int, fetcher Fetcher) {
        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)
        for _,u := range urls {
            if used[u] == false {
                used[u] = true
                Crawl(u, depth-1, fetcher)
            }
        }
        return
    }

为了使其并发,我在对Crawl函数的调用之前添加了go命令,但是该程序不是递归地调用Crawl函数,而是仅找到“http://golang.org/”页面,而找不到其他页面。

将go命令添加到Crawl函数的调用中时,为什么程序无法正常工作?

最佳答案

问题似乎是,您的过程在所有URL都可以遵循之前就已退出
由爬行者。由于存在并发性,因此main()过程在
worker 完成了。

为了避免这种情况,您可以使用 sync.WaitGroup :

func Crawl(url string, depth int, fetcher Fetcher, wg *sync.WaitGroup) {
    defer wg.Done()
    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)
    for _,u := range urls {
        if used[u] == false {
           used[u] = true
           wg.Add(1)
           go Crawl(u, depth-1, fetcher, wg)
        }
    }
    return
}

并按以下方式在Crawl中调用main:
func main() {
    wg := &sync.WaitGroup{}

    Crawl("http://golang.org/", 4, fetcher, wg)

    wg.Wait()
}

另外,don't rely on the map being thread safe

09-25 17:01