我正在尝试解决练习:Web Crawler在本练习中,您将使用 Go 的并发特性来并行化网络爬虫。修改 Crawl 函数以并行获取 URL,而不需要两次获取相同的 URL。我应该什么时候检查所有 url 是否已经被抓取?(或者我怎么知道是否不再有数据排队?)package mainimport ( "fmt")type Result struct { Url string Depth int}type Stor struct { Queue chan Result Visited map[string]int} func NewStor() *Stor { return &Stor{ Queue: make(chan Result,1000), Visited: map[string]int{}, }}type Fetcher interface { // Fetch returns the body of URL and // a slice of URLs found on that page. Fetch(url string) (body string, urls []string, err error)}// Crawl uses fetcher to recursively crawl// pages starting with url, to a maximum of depth.func Crawl(res Result, fetcher Fetcher, stor *Stor) { defer func() { /* if len(stor.Queue) == 0 { close(stor.Queue) } */ // this is wrong, it makes the channel closes too early }() if res.Depth <= 0 { return } // TODO: Don't fetch the same URL twice. url := res.Url stor.Visited[url]++ if stor.Visited[url] > 1 { fmt.Println("skip:",stor.Visited[url],url) return } body, urls, err := fetcher.Fetch(url) if err != nil { fmt.Println(err) return } fmt.Printf("found: %s %q\n", url, body) for _, u := range urls { stor.Queue <- Result{u,res.Depth-1} } return}func main() { stor := NewStor() Crawl(Result{"http://golang.org/", 4}, fetcher, stor) for res := range stor.Queue { // TODO: Fetch URLs in parallel. go Crawl(res,fetcher,stor) }}// fakeFetcher is Fetcher that returns canned results.type fakeFetcher map[string]*fakeResulttype fakeResult struct { body string urls []string}func (f fakeFetcher) Fetch(url string) (string, []string, error) { if res, ok := f[url]; ok { return res.body, res.urls, nil } return "", nil, fmt.Errorf("not found: %s", url)}输出是一个死锁,因为stor.Queue通道从未关闭。
2 回答
萧十郎
TA贡献1815条经验 获得超13个赞
检查len
通道的始终是一场竞赛,您不能将其用于任何类型的同步。
生产者总是关闭通道的一方,因为尝试在关闭的通道上发送是一个致命的错误。不要在此处使用延迟,只需在完成发送后关闭通道即可
- 2 回答
- 0 关注
- 159 浏览
添加回答
举报
0/150
提交
取消