Sam*_*ums 10 concurrency recursion go goroutine
我想知道解决这个问题的惯用方法(目前抛出死锁错误),递归分支未知次数,所以我不能简单地关闭通道.
http://play.golang.org/p/avLf_sQJj_
我通过将指针传递给一个数字并递增它来使它工作,我已经研究过使用同步等待组.我没有感觉(我可能错了),我想出了一个优雅的解决方案.我见过的Go示例往往简单,聪明,简洁.
这是Tour of Go的最后一个练习,https://tour.golang.org/#73
你知道'Go程序员怎么会'管理这个?任何帮助,将不胜感激.我想从一开始就学好.
sync.WaitGroup您可以扩展在解析的 url 上发送的结果并包含找到的新 URL 的数量,而不是涉及。在主循环中,只要有东西要收集,您就会继续读取结果。
在您的情况下,找到的 url 数量将是生成的 go 例程的数量,但不一定需要如此。我个人会生成或多或少固定数量的获取例程,因此您不会打开太多 HTTP 请求(或者至少您可以控制它)。那么你的主循环不会改变,因为它不关心提取是如何执行的。这里重要的事实是,您需要为每个 url \xe2\x80\x93 发送结果或错误。我已经修改了此处的代码,因此当深度已经为 1 时,它不会生成新的例程。
\n\n该解决方案的一个副作用是您可以轻松地打印主循环中的进度。
\n\n这是操场上的示例:
\n\nhttp://play.golang.org/p/BRlUc6bojf
\n\npackage main\n\nimport (\n "fmt"\n)\n\ntype Fetcher interface {\n // Fetch returns the body of URL and\n // a slice of URLs found on that page.\n Fetch(url string) (body string, urls []string, err error)\n}\n\ntype Res struct {\n url string\n body string\n found int // Number of new urls found\n}\n\n// Crawl uses fetcher to recursively crawl\n// pages starting with url, to a maximum of depth.\nfunc Crawl(url string, depth int, fetcher Fetcher, ch chan Res, errs chan error, visited map[string]bool) {\n body, urls, err := fetcher.Fetch(url)\n visited[url] = true\n if err != nil {\n errs <- err\n return\n }\n\n newUrls := 0 \n if depth > 1 {\n for _, u := range urls {\n if !visited[u] {\n newUrls++\n go Crawl(u, depth-1, fetcher, ch, errs, visited)\n }\n }\n }\n\n // Send the result along with number of urls to be fetched\n ch <- Res{url, body, newUrls}\n\n return\n}\n\nfunc main() {\n ch := make(chan Res)\n errs := make(chan error)\n visited := map[string]bool{}\n go Crawl("http://golang.org/", 4, fetcher, ch, errs, visited)\n tocollect := 1\n for n := 0; n < tocollect; n++ {\n select {\n case s := <-ch:\n fmt.Printf("found: %s %q\\n", s.url, s.body)\n tocollect += s.found\n case e := <-errs:\n fmt.Println(e)\n }\n }\n\n}\n\n// fakeFetcher is Fetcher that returns canned results.\ntype fakeFetcher map[string]*fakeResult\n\ntype fakeResult struct {\n body string\n urls []string\n}\n\nfunc (f fakeFetcher) Fetch(url string) (string, []string, error) {\n if res, ok := f[url]; ok {\n return res.body, res.urls, nil\n }\n return "", nil, fmt.Errorf("not found: %s", url)\n}\n\n// fetcher is a populated fakeFetcher.\nvar fetcher = fakeFetcher{\n "http://golang.org/": &fakeResult{\n "The Go Programming Language",\n []string{\n "http://golang.org/pkg/",\n "http://golang.org/cmd/",\n },\n },\n "http://golang.org/pkg/": &fakeResult{\n "Packages",\n []string{\n "http://golang.org/",\n "http://golang.org/cmd/",\n "http://golang.org/pkg/fmt/",\n "http://golang.org/pkg/os/",\n },\n },\n "http://golang.org/pkg/fmt/": &fakeResult{\n "Package fmt",\n []string{\n "http://golang.org/",\n "http://golang.org/pkg/",\n },\n },\n "http://golang.org/pkg/os/": &fakeResult{\n "Package os",\n []string{\n "http://golang.org/",\n "http://golang.org/pkg/",\n },\n },\n}\nRun Code Online (Sandbox Code Playgroud)\n\n是的,遵循@jimt的建议并确保对地图线程的访问是安全的。
\n