3

私は golang ツアーを進めており、クロールを繰り返さずに並行してクロールするように Web クローラーを変更する最後の演習に取り組んでいます ( 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/ " ページのみを検出し、他のページは検出しません。

関数 Crawl の呼び出しに go コマンドを追加すると、プログラムが動作しないのはなぜですか?

4

2 に答える 2

9

The problem seems to be, that your process is exiting before all URLs can be followed by the crawler. Because of the concurrency, the main() procedure is exiting before the workers are finished.

To circumvent this, you could use 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
}

And call Crawl in main as follows:

func main() {
    wg := &sync.WaitGroup{}

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

    wg.Wait()
}

Also, don't rely on the map being thread safe.

于 2012-09-03T15:09:22.453 に答える