title: Tour of Go exercise #10: Crawler
body: <p>I'm going through the Go Tour and I feel like I have a pretty good understanding of the language except for concurrency.</p>
  <p><a href="https://tour.golang.org/concurrency/10" rel="noreferrer">slide 10</a> is an exercise that asks the reader to parallelize a web crawler (and to make it not cover repeats but I haven't gotten there yet.)</p>
  <p>Here is what I have so far:</p>
  <pre><code>func Crawl(url string, depth int, fetcher Fetcher, ch chan string) {
      if depth &lt;= 0 {
          return
      }
  
      body, urls, err := fetcher.Fetch(url)
      if err != nil {
          ch &lt;- fmt.Sprintln(err)
          return
      }
  
      ch &lt;- fmt.Sprintf(&quot;found: %s %q\n&quot;, url, body)
      for _, u := range urls {
          go Crawl(u, depth-1, fetcher, ch)
      }
  }
  
  func main() {
      ch := make(chan string, 100)
      go Crawl(&quot;http://golang.org/&quot;, 4, fetcher, ch)
  
      for i := range ch {
          fmt.Println(i)
      }
  }
  </code></pre>
  <p>My question is, where do I put the <code>close(ch)</code> call.</p>
  <p>If I put a <code>defer close(ch)</code> somewhere in the <code>Crawl</code> method, then the program ends up writing to a closed channel from one of the spawned goroutines, because the call to <code>Crawl</code> will return before the spawned goroutines do.</p>
  <p>If I omit the call to <code>close(ch)</code>, as I demonstrate it, the program deadlocks in the main function ranging the channel because the channel is never closed when all goroutines has returned.</p>