go tour 练习 https://tour.go-zh.org/concurrency/10
package main import ( "fmt" "sync" "time" ) type Fetcher interface { // Fetch 返回 URL 的 body 内容,并且将在这个页面上找到的 URL 放到一个 slice 中。 Fetch(url string) (body string, urls []string, err error) } // SafeCounter 的并发使用是安全的。 type SafeUrlMap struct { v map[string]bool mux sync.Mutex } func (c *SafeUrlMap) Put(key string) { c.mux.Lock() c.v[key] = true c.mux.Unlock() } func (c *SafeUrlMap) Contains(key string) bool { c.mux.Lock() defer c.mux.Unlock() _, ok := c.v[key] return ok } type Resp struct { url string body string } var urlMap *SafeUrlMap = &SafeUrlMap{v: make(map[string]bool)} // Crawl 使用 fetcher 从某个 URL 开始递归的爬取页面,直到达到最大深度。 func Crawl(url string, depth int, fetcher Fetcher, ch chan Resp) { if depth <= 0 { return } urlMap.Put(url) body, urls, err := fetcher.Fetch(url) if err != nil { fmt.Println(err) return } ch <- Resp{url:url, body:body} for _, u := range urls { if urlMap.Contains(u) { fmt.Printf("Have Processed: %s\n", u) continue } go Crawl(u, depth-1, fetcher, ch) } return } func main() { ch := make(chan Resp) go Crawl("http://golang.org/", 4, fetcher, ch) boom := time.After(3 * time.Second) for { select { case r := <-ch: fmt.Printf("found: %s %q\n", r.url, r.body) boom = time.After(3 * time.Second) case <-boom: fmt.Printf("time out\n") return } } } // fakeFetcher 是返回若干结果的 Fetcher。 type fakeFetcher map[string]*fakeResult type 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) } // fetcher 是填充后的 fakeFetcher。 var fetcher = fakeFetcher{ "http://golang.org/": &fakeResult{ "The Go Programming Language", []string{ "http://golang.org/pkg/", "http://golang.org/cmd/", }, }, "http://golang.org/pkg/": &fakeResult{ "Packages", []string{ "http://golang.org/", "http://golang.org/cmd/", "http://golang.org/pkg/fmt/", "http://golang.org/pkg/os/", }, }, "http://golang.org/pkg/fmt/": &fakeResult{ "Package fmt", []string{ "http://golang.org/", "http://golang.org/pkg/", }, }, "http://golang.org/pkg/os/": &fakeResult{ "Package os", []string{ "http://golang.org/", "http://golang.org/pkg/", }, }, }
有疑问加站长微信联系(非本文作者)