0

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/

これは、プログラムを並列実行しようとしたときにのみ発生します。線形に実行すると、すべての URL が正しく検出されます。

注:これを正しく行っていない場合(つまり、並列処理)、お詫び申し上げます。

4

1 に答える 1

1
  • ゴルーチンに注意してください。
  • メイン ルーチン、またはmain()func が戻ると、他のすべての go ルーチンはすぐに強制終了されるためです。
  • あなたは再帰的であるように見えますが、そうではありません。つまり、他のルーチンCrawl()を待たずにすぐに戻ります。Crawl()そしてCrawl()、 によって呼び出された最初のmain()が返された場合、main()func はその使命が達成されたと見なすことを知っています。
  • できることは、main()func が最後Crawl()に戻るまで待機させることです。syncパッケージ、またはがchan役立ちます。
  • おそらく、私が数か月前に行った、これ最後の解決策を見ることができます。

    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)
    }
    
于 2012-09-01T05:04:33.633 に答える