2017-09-24 1 views
0

Comme les hits mentionnés dans l'exemple de Crawl d'un 'Tour of Go', j'ai modifié la fonction d'exploration et je me demande juste pourquoi le 'go Crawl' n'a pas réussi à engendrer un autre thread comme une seule URL a été trouvée imprimée.goroutine n'a pas pris effet dans l'exemple Crawl de 'A Tour of Go'

Y at-il un problème avec ma modification?

Liste ma modification comme ci-dessous,

// Crawl uses fetcher to recursively crawl 
// pages starting with url, to a maximum of depth. 
func Crawl(url string, depth int, fetcher Fetcher) { 
    // TODO: Fetch URLs in parallel. 
    // TODO: Don't fetch the same URL twice. 
    // This implementation doesn't do either: 
    if depth <= 0 { 
     fmt.Printf("depth <= 0 return") 
     return 
    } 
    body, urls, err := fetcher.Fetch(url) 
    if err != nil { 
     fmt.Println(err) 
     return 
    } 
    fmt.Printf("found: %s %q\n", url, body) 
    crawled.mux.Lock() 
    crawled.c[url]++ 
    crawled.mux.Unlock() 
    for _, u := range urls { 
     //crawled.mux.Lock() 
     if cnt, ok := crawled.c[u]; ok { 
      cnt++ 
     } else { 
      fmt.Println("go ...", u) 
      go Crawl(u, depth-1, fetcher) 
     } 
     //crawled.mux.Unlock() 
     //Crawl(u, depth-1, fetcher) 
    } 
    return 
} 


type crawledUrl struct { 
    c map[string]int 
    mux sync.Mutex 
} 

var crawled = crawledUrl{c: make(map[string]int)} 

Répondre

0

Dans votre programme, vous avez sans aucun outil synchronisé pour vos routines de go.

Le comportement de ce code est donc indéfini. Peut-être que le fil principal va bientôt se terminer. S'il vous plaît rappelez-vous que la routine go principale ne bloquera jamais attendre d'autres routines aller pour la résiliation, seulement si vous utilisez explicitement une sorte d'util pour synchroniser l'exécution des routines go.

Comme des canaux ou des utilitaires de synchronisation utiles.

Laissez-moi vous aider à donner une version.

type fetchState struct { 
    mu  sync.Mutex 
    fetched map[string]bool 
} 

func (f *fetchState) CheckAndMark(url string) bool { 
    defer f.mu.Unlock() 

    f.mu.Lock() 
    if f.fetched[url] { 
     return true 
    } 
    f.fetched[url] = true 
    return false 
} 

func mkFetchState() *fetchState { 
    f := &fetchState{} 
    f.fetched = make(map[string]bool) 
    return f 
} 

func CrawlConcurrentMutex(url string, fetcher Fetcher, f *fetchState) { 
    if f.CheckAndMark(url) { 
     return 
    } 

    body, urls, err := fetcher.Fetch(url) 
    if err != nil { 
     fmt.Println(err) 
     return 
    } 
    fmt.Printf("found: %s %q\n", url, body) 
    var done sync.WaitGroup 
    for _, u := range urls { 
     done.Add(1) 
     go func(u string) { 
      defer done.Done() 
      CrawlConcurrentMutex(u, fetcher, f) 
     }(u) // Without the u argument there is a race 
    } 
    done.Wait() 
    return 
} 

S'il vous plaît attention à l'utilisation de sync.WaitGroup, s'il vous plaît consulter le doc et vous pouvez comprendre toute l'histoire.