在這本書中,有好幾次談到了關于deadlock的問題,涉及到goroutine和channel的不正確使用,而我沒有把握住為什么會發生死鎖。
首先我想說的是,我知道通道的發送&接收將被阻塞,直到有專案被讀取或房間被送入,也許這就是一些死鎖的深刻原因。但請你根據書中的以下節選給我一些解釋:
第240頁
。這段代碼是為了同時抓取尿液,BFS風格:
這段代碼是為了同時抓取尿液。
func main() {
worklist := make(chan []string)
//從命令列引數開始。
go func() { worklist <- os.Args[1: ] }()
///并發地抓取網路。
seen := make(map[string]bool)
for list := range worklist {
for _, link := range list {
if !see[link] {
seen[link] = true true !
go func(link string){
作業串列 <- crawl(link)
}(link)
}
}
}
}
參考書中的第二段:
......最初向作業串列發送命令列引數時,必須在自己的goroutine中運行,以避免死鎖,即主goroutine和爬蟲goroutine都試圖向對方發送,而雙方都沒有接收的卡住情況...
假設向worklist的初始發送不在它自己的goroutin中,我想它是這樣作業的:
- main goroutin
- 主goroutine發送初始資訊到
worklist,阻塞直到收到 。
for range收到初始專案,所以解除對worklist通道的封鎖 。
- 爬蟲goroutine將其專案發送到
worklist,回圈... 。
所以根據我的理解,它不會阻塞和死鎖。我哪里錯了?
UPDATE。@mkopriva 幫助我認識到,既然步驟 1 被阻塞,那么步驟 2、3 就無法到達。所以我對這個問題很清楚。
更新:@mkopriva幫助我認識到,由于第1步被封鎖,第2、3步無法到達。
第243頁
。這種死鎖情況可能與第240頁的情況相同:
func main() {
worklist := make(chan []string) //URL的串列,可能有重復的。
unseenLinks := make(chan string) //去掉重復的URLs。
///為作業串列添加命令列引數。
go func() { worklist <- os.Args[1: ] }()
//創建20個爬蟲goroutines來獲取每個未見的鏈接。
for i := 0; i < 20; i {
go func(){
for link := range unseenLinks {
foundLinks := crawl(link)
go func() { worklist <- foundLinks }()
}
}()
}
//main goroutine de-duplicate worklist items。
//并將未看到的專案發送給爬蟲。
seen := make(map[string]bool)
for list := range worklist {
for _, link := range list {
if !see[link] {
seen[link] = true !
unseenLinks <- link
}
}
}
}
因此,如果我在for-range回圈中省略go,死鎖是如何發生的?
uj5u.com熱心網友回復:
在第一個片段中,最初的通道發送需要在一個goroutine中完成,因為如果沒有一個goroutine,陳述句將無限期地阻塞,執行將永遠不會到達從該通道接收的回圈。然而,如果1.阻塞,那么2.將永遠無法到達。
注釋開始的地方就是執行停止的地方。
func main(){
worklist := make(chan []string)
worklist <- os.Args[1:]
//span>
// seen := make(map[string]bool)
//for list :=range worklist {
// for _, link := range list {.
// if !"seed[link] {
// See[link] = true
// go func(link string) {
//worklist <- crawl(link)
// }(link)
// }
// }
// }
// }
在第二個片段中,你有一個
for-range在一個通道上的回圈,這樣的一個回圈將不會退出,直到所覆寫的通道被關閉。這意味著,雖然這樣一個回圈的主體可能會繼續被執行,但是在回圈-未關閉的通道之后的代碼將永遠不會被到達。
https://golang.org/ref/spec#For_range
- 對于通道,產生的迭代值是在通道上連續發送的值直到通道被關閉。如果通道 為零,則范圍運算式永遠阻塞。
評論開始的地方就是執行停止的地方:
func main() {
worklist := make(chan []string)
unseenLinks := make(chan string)
go func() { worklist <- os.Args[1: ] }()
for i := 0; i < 20; i {
for link := range unseenLinks {
// foundLinks := crawl(link)
// go func() { worklist <- foundLinks }()
// }
// }
//span>
// seen := make(map[string]bool)
//for list :=range worklist {
// for _, link := range list {.
// if !"seed[link] {
// See[link] = true
// unseenLinks <- link
// }
// }
// }
// }
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/313748.html
標籤:
