私はゴーツアーを行っていますが、並行性を除いて、言語をかなりよく理解しているように感じます。
スライド10は、読者にWebクローラーを並列化するように求める演習です(繰り返しをカバーしないようにしますが、まだそこに到達していません)。
これが私がこれまでに持っているものです:
func Crawl(url string, depth int, fetcher Fetcher, ch chan string) {
if depth <= 0 {
return
}
body, urls, err := fetcher.Fetch(url)
if err != nil {
ch <- fmt.Sprintln(err)
return
}
ch <- fmt.Sprintf("found: %s %q\n", url, body)
for _, u := range urls {
go Crawl(u, depth-1, fetcher, ch)
}
}
func main() {
ch := make(chan string, 100)
go Crawl("http://golang.org/", 4, fetcher, ch)
for i := range ch {
fmt.Println(i)
}
}
私の質問は、どこにclose(ch)
電話をかけるかです。
defer close(ch)
メソッドのどこかに置くとCrawl
、プログラムは、スポーンされたゴルーチンの1つから閉じたチャネルに書き込むことになります。これは、の呼び出しがCrawl
、スポーンされたゴルーチンよりも先に返されるためです。
私が示すように、への呼び出しを省略するとclose(ch)
、すべてのゴルーチンが戻ったときにチャネルが閉じられることはないため、プログラムはチャネルの範囲を指定するmain関数でデッドロックします。