Advertisement
cmiN

go-routines

Apr 16th, 2025
258
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 2.37 KB | Source Code | 0 0
  1. package main
  2.  
  3. import (
  4.     "fmt"
  5.     "sync"
  6. )
  7.  
  8. type Fetcher interface {
  9.     // Fetch returns the body of URL and
  10.     // a slice of URLs found on that page.
  11.     Fetch(url string) (body string, urls []string, err error)
  12. }
  13.  
  14.  
  15. type Seen struct {
  16.     mu sync.Mutex
  17.     seen map[string]bool   
  18. }
  19.  
  20. func (s *Seen) isSeen(url string) bool {
  21.     s.mu.Lock()
  22.     defer s.mu.Unlock()
  23.     if val, ok := s.seen[url]; ok {
  24.         return val
  25.     }
  26.     return false
  27. }
  28.  
  29. func (s *Seen) markSeen(url string) {
  30.     s.mu.Lock()
  31.     defer s.mu.Unlock()
  32.     s.seen[url] = true
  33. }
  34.  
  35. var ss Seen = Seen{seen: make(map[string]bool)}
  36.  
  37. // Crawl uses fetcher to recursively crawl
  38. // pages starting with url, to a maximum of depth.
  39. func Crawl(url string, depth int, fetcher Fetcher, wg *sync.WaitGroup) {
  40.     // TODO: Fetch URLs in parallel.
  41.     // TODO: Don't fetch the same URL twice.
  42.     // This implementation doesn't do either:
  43.     defer wg.Done()
  44.    
  45.     if depth <= 0 {
  46.         return
  47.     }
  48.    
  49.     body, urls, err := fetcher.Fetch(url)
  50.     if err != nil {
  51.         fmt.Println(err)
  52.         return
  53.     }
  54.     fmt.Printf("found: %s %q\n", url, body)
  55.     for _, u := range urls {
  56.         if ss.isSeen(u) {
  57.             continue
  58.         }
  59.         ss.markSeen(u)
  60.         wg.Add(1)
  61.         go Crawl(u, depth-1, fetcher, wg)
  62.     }
  63.     return
  64. }
  65.  
  66. func main() {
  67.     var wg sync.WaitGroup
  68.     defer wg.Wait()
  69.     wg.Add(1)
  70.     go Crawl("https://golang.org/", 4, fetcher, &wg)
  71. }
  72.  
  73. // fakeFetcher is Fetcher that returns canned results.
  74. type fakeFetcher map[string]*fakeResult
  75.  
  76. type fakeResult struct {
  77.     body string
  78.     urls []string
  79. }
  80.  
  81. func (f fakeFetcher) Fetch(url string) (string, []string, error) {
  82.     if res, ok := f[url]; ok {
  83.         return res.body, res.urls, nil
  84.     }
  85.     return "", nil, fmt.Errorf("not found: %s", url)
  86. }
  87.  
  88. // fetcher is a populated fakeFetcher.
  89. var fetcher = fakeFetcher{
  90.     "https://golang.org/": &fakeResult{
  91.         "The Go Programming Language",
  92.         []string{
  93.             "https://golang.org/pkg/",
  94.             "https://golang.org/cmd/",
  95.         },
  96.     },
  97.     "https://golang.org/pkg/": &fakeResult{
  98.         "Packages",
  99.         []string{
  100.             "https://golang.org/",
  101.             "https://golang.org/cmd/",
  102.             "https://golang.org/pkg/fmt/",
  103.             "https://golang.org/pkg/os/",
  104.         },
  105.     },
  106.     "https://golang.org/pkg/fmt/": &fakeResult{
  107.         "Package fmt",
  108.         []string{
  109.             "https://golang.org/",
  110.             "https://golang.org/pkg/",
  111.         },
  112.     },
  113.     "https://golang.org/pkg/os/": &fakeResult{
  114.         "Package os",
  115.         []string{
  116.             "https://golang.org/",
  117.             "https://golang.org/pkg/",
  118.         },
  119.     },
  120. }
  121.  
Tags: tutorial TOUR go
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement