2017-09-11 32 views
0

我正在閱讀「圍棋之旅」,並且一直在編輯大部分課程以確保我完全理解它們。我有一個關於提供給下面的練習回答的問題:https://tour.golang.org/concurrency/10這可以在這裏找到:https://github.com/golang/tour/blob/master/solutions/webcrawler.go「旅行之旅」中的頻道說明網絡爬行器練習

我有一個關於下節問題:

done := make(chan bool) 
for i, u := range urls { 
    fmt.Printf("-> Crawling child %v/%v of %v : %v.\n", i, len(urls), url, u) 
    go func(url string) { 
     Crawl(url, depth-1, fetcher) 
     done <- true 
    }(u) 
} 
for i, u := range urls { 
    fmt.Printf("<- [%v] %v/%v Waiting for child %v.\n", url, i, len(urls), u) 
    <-done 
} 
fmt.Printf("<- Done with %v\n", url) 

什麼用途添加和去除真通道done和運行兩個單獨的for循環有?這只是阻止,直到去例程完成?我知道這是一個示例練習,但是這種方式並沒有打破首先創建新線程的觀點?

爲什麼不通過撥打go Crawl(url, depth-1, fetcher)而沒有2nd for循環和done頻道?是因爲所有變量的共享內存空間?

謝謝!

回答

2

第一個for循環計劃多個goroutines運行並遍歷一片urls。

第二個循環在每個url上阻塞,等待其相應的Crawl()調用完成。所有Crawl()rs將運行,並行工作並阻止退出,直到主線程有機會在每個url的done頻道上收到消息。

在我看來,更好的實現方法是使用sync.WaitGroup。此代碼可能會記錄錯誤的事情,具體取決於每個調用所需的時間長度,除非鎖定fetcher

如果你想確保完成Crawl() ING的網址,你可以在做渠道的類型更改爲stringCrawl()完成後發送url而不是true。然後,我們可以在第二個循環中收到url

例子:

done := make(chan string) 
for _, u := range urls { 
    fmt.Printf("-> Crawling %s\n", u) 
    go func(url string) { 
     Crawl(url, depth-1, fetcher) 
     done <- url 
    }(u) 
} 
for range urls { 
    fmt.Printf("<- Waiting for next child\n") 
    u := <-done 
    fmt.Printf(" Done... %s\n", u) 
} 
+0

感謝您的解釋!我在自己的研究中發現了WaitGroup,它類似於我從Python中熟悉的一些併發概念。但是,我認爲我應該嘗試並理解如何僅使用前面課程中提到的內容來解決練習。 跟進你的解釋,你是說每個爬蟲都有它自己的渠道嗎?這樣做會更有意義,並且可以解釋爲什麼會有與每個Crawler相對應的另一個循環。我覺得所有變量都在一個共享空間中,並且認爲總共只有一個通道。 – leif

+0

@leif每個爬蟲沒有自己的頻道 - 只有一個頻道。在執行每個「抓取」功能後,「url」將通過相同的通道發送。您可能需要閱讀更多內容並在頻道上進行一些練習。 Donovan和Kernighan編寫的Go Programming Language是一本很好的書。 – Ravi

+0

謝謝@Ravi,我回復了未經編輯的Blaskovicz的文章,現在更清楚地表明,我原本以爲只有一個頻道。我會檢查你推薦的書,謝謝! – leif