【问题标题】:Why does the function return early?为什么函数会提前返回?
【发布时间】:2012-09-01 02:23:00
【问题描述】:

我刚刚开始学习围棋,并且一直在巡回演出。最后一个练习是编辑一个网络爬虫以并行且不重复地爬取。

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

注意:如果我做的不对(我的意思是并行性),那么我道歉。

【问题讨论】:

    标签: concurrency go


    【解决方案1】:
    • 小心使用 goroutine。
    • 因为当主例程或main() func 返回时,所有其他go 例程将立即被杀死。
    • 您的Crawl() 似乎是递归的,但事实并非如此,这意味着它会立即返回,而不是等待其他Crawl() 例程。而且您知道,如果由main() 调用的第一个Crawl() 返回,则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)
      }
      

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-14
    • 1970-01-01
    • 2014-02-22
    相关资源
    最近更新 更多