4

私は go ツアーを実行し、Web クローラーの演習を終了しましたが、すべての結果を印刷するために使用した手法は非効率的である可能性があると思います。

これが私のコードです。クロールとメイン機能のみを編集したので、それを投稿します。演習へのリンクは次のとおりです ( http://tour.golang.org/#70 )

    var used = make(map[string]bool)

    func Crawl(url string, depth int, fetcher Fetcher, results chan string) {
        if depth <= 0 {
            return
        }
        body, urls, err := fetcher.Fetch(url)
        if err != nil {
            results <- fmt.Sprintf("%v",err)
            return
        }
        results <-fmt.Sprintf("\nfound: %s %q\n", url, body)
        for _,u := range urls {
            if used[u] == false {
                used[u] = true
                go Crawl(u, depth-1, fetcher, results)
            }
        }
        return
    }
    //------------------------------------------------------------
    func main() {
        used["http://golang.org/"] = true
        results := make(chan string)
        go Crawl("http://golang.org/", 4, fetcher, results)
        for i := 0; i < len(used); i++ {
            fmt.Println(<-results)
        }
    }

メインで「for i < len(used)」行を使用して、出力する結果がある場合にのみ結果の値が出力されるようにします。私はちょうど使用することはできません

    for i := range results

クロール機能で「close(results)」を再帰的に使うのは難しいのですが、私のやり方では毎回使う変数の長さを調べなければなりません。

これを行うより良い方法はありますか?

4

1 に答える 1

3

ゴルーチンのコレクションが終了するのを待つには、sync.WaitGroup.

I believe you'll find the example in the official documentation very familiar..

http://golang.org/pkg/sync/#example_WaitGroup

Quoting:

var wg sync.WaitGroup
var urls = []string{
    "http://www.golang.org/",
    "http://www.google.com/",
    "http://www.somestupidname.com/",
}
for _, url := range urls {
    // Increment the WaitGroup counter.
    wg.Add(1)
    // Launch a goroutine to fetch the URL.
    go func(url string) {
        // Fetch the URL.
        http.Get(url)
        // Decrement the counter.
        wg.Done()
    }(url)
}
// Wait for all HTTP fetches to complete.
wg.Wait()

これは、すべての作業が完了するまでブロックされます。

収集した結果を段階的に出力したい場合、最も簡単な方法は、フェッチャー自体で実行することです。

于 2012-09-01T17:22:05.873 に答える