练习:Web爬网程序-打印不起作用

时间:2019-02-13 03:17:04

标签: go

  

我是golang新手,目前正在Exercise: Web Crawler上工作。

我只是在调用func Crawl的每个位置之前都加上了关键字“ go”,并希望它可以并行化,但是fmt.Printf不起作用并且什么也不打印。除此代码外,原始代码没有其他更改。有人想帮我吗?

func Crawl(url string, depth int, fetcher Fetcher) {
    // TODO: Fetch URLs in parallel.
    // TODO: Don't fetch the same URL twice.
    // This implementation doesn't do either:
    if depth <= 0 {
        return
    }
    body, urls, err := fetcher.Fetch(url)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("found: %s %q\n", url, body)
    for _, u := range urls {
        go Crawl(u, depth-1, fetcher)
    }
    return
}

func main() {
    go Crawl("https://golang.org/", 4, fetcher)
}

1 个答案:

答案 0 :(得分:3)

根据spec

  

通过初始化主程序包然后调用函数main开始程序执行。当该函数调用返回时,程序退出。它不等待其他(非主)goroutine完成。

因此,您必须显式等待另一个goroutine以main()函数结尾。

一种方法是简单地在time.Sleep()函数的末尾添加main(),直到您认为另一个goroutine结束(例如,在这种情况下可能为1秒)。

更清洁的方式使用sync.WaitGroup如下:

func Crawl(wg *sync.WaitGroup, url string, depth int, fetcher Fetcher) {
    defer wg.Done()
    if depth <= 0 {
        return
    }
    body, urls, err := fetcher.Fetch(url)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("found: %s %q\n", url, body)
    for _, u := range urls {
        wg.Add(1)
        go Crawl(wg, u, depth-1, fetcher)
    }
    return
}

func main() {
    wg := &sync.WaitGroup{}
    wg.Add(1)
    // first call does not need to be goroutine since its subroutine is goroutine.
    Crawl(wg, "https://golang.org/", 4, fetcher)
    //time.Sleep(1000 * time.Millisecond)
    wg.Wait()
}

此代码将计数器存储在WaitGroup中,使用wg.Add()对其进行递增,使用wg.Done()进行递减,并使用wg.Wait()等到其变为零。

在操场上进行确认:https://play.golang.org/p/WqQBqe6iFLp