并发 – 如何从并发和递归函数中打印结果?

我一直在浏览,我已经完成了网络爬虫练习,但我认为我用来打印所有结果的技术可能效率低下.

这是我的代码.我只编辑了抓取和主要功能,所以我只是发布它.这是演习的链接(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)
        }
    }

我在main中使用“for i< len(used)”行来确保仅在打印结果时才打印结果中的值.我不能只使用

    for i := range results

因为爬行函数很难使用“close(results)”,因为它是递归的,但是按照我这样做的方式,我必须每次都找到变量的长度.

有一个更好的方法吗?

最佳答案 要等待完成goroutine的集合,请使用sync.WaitGroup.

我相信你会在官方文档中找到非常熟悉的例子.

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

引用:

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()

这将阻止所有工作完成.

如果您真的想在收集结果时逐步打印结果,最简单的方法是在提取器本身中执行此操作.

点赞