package main import ( "context" "fmt" "log" "net/url" "sync" ) func classic(startURL url.URL, maxConcurrency, maxURLs int) { worklist := make(chan []url.URL) var numPendingSends int numPendingSends++ go func() { worklist <- []url.URL{startURL} }() // Crawl the web concurrently. seen := make(map[url.URL]bool) count := 1 ctx, cancel := context.WithCancel(context.Background()) var wg sync.WaitGroup sema := make(chan struct{}, maxConcurrency) loop: for ; numPendingSends > 0; numPendingSends-- { batch := <-worklist for _, u := range batch { if !seen[u] { fmt.Printf("%d. %s\n", count, &u) count++ seen[u] = true if len(seen) == maxURLs { break loop } numPendingSends++ wg.Go(func() { sema <- struct{}{} defer func() { <-sema }() select { case <-ctx.Done(): return case worklist <- getBatch(u): } }) } } } cancel() wg.Wait() } func getBatch(u url.URL) []url.URL { doc, err := fetch(u) if err != nil { log.Print(err) } batch := findURLs(u, doc) return batch }