2012-09-01 93 views
0

我刚刚开始学习,并一直在通过巡回演练。最后一个练习是编辑一个网页爬虫并行爬网,不需要重复。为什么函数返回提前?

这里是链接到练习: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都可以正确找到。

注意:如果我没有这样做(我的意思是并行),那么我很抱歉。

回答

1
  • 小心使用goroutine。
  • 因为当主例程或main()函数返回时,所有其他例程都会立即被杀死。
  • 你的Crawl()看起来像递归,但它不是,这意味着它会立即返回,而不是等待其他Crawl()例程。而且你知道,如果第一个Crawl()(由main()调用)返回,那么main()函数就认为它的任务已完成。
  • 你可以做的是让main() func等到最后的Crawl()返回。 sync包或chan将有所帮助。
  • 你也许可以看看的this最后的解决方案,这是我几个月前做的:

    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) 
    } 
    
+0

没错http://www.youtube.com/watch?v=f6kdp27TYZs&feature=player_detailpage #t = 442s这里是解释goroutines和主要的长袍派克 – user1462442