Я прохожу через тур, и я чувствую, что у меня довольно хорошее понимание языка, за исключением параллелизма.
На слайде 72 есть упражнение, которое просит читателя распараллеливать искатель веб-страниц (и чтобы он не перекрывал повторы, но я еще не получил его).
Вот что я имею до сих пор:
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
, то я заканчиваю запись на закрытый канал в одном из порожденных goroutines, так как метод завершит выполнение до того, как порожденные goroutines сделают.
Если я опускаю вызов на close(ch)
, как показано в моем примере кода, программа блокируется после завершения выполнения всех goroutines, но основной поток все еще ожидает канал в цикле for, поскольку канал никогда не был закрыт.