有Select 的Goroutine 不會停止,除非加上列印語句
在Go Tour 練習#71 中,使用不帶預設值的select語句可能會導致無限循環,從而阻止goroutine 退出。使用 nogood 參數執行 71_hang.go 時會遇到此問題,但使用 ok 參數則不會。
兩個場景之間的差異在於預設有額外的 fmt.Print("") 語句select 語句的情況。預設情況下,選擇區塊直到其中一個通道有訊息要接收。然而,在預設情況下,即使沒有通道有訊息可用,select 也會執行預設語句。
在原始程式碼中,沒有 fmt.Print("") 語句,select 語句輸入了一個無限循環,因為沒有可用訊息的通道,並且預設情況下不執行任何操作來允許 goroutine 進行調度。添加 fmt.Print("") 語句允許調度程序調度其他 goroutine 並打破無限循環。
或者,可以修改程式碼以非阻塞方式使用 select,從而允許其他 goroutine才能正常運作。這可以透過刪除預設語句並使用單獨的 if 語句來檢查抓取計數器是否已達到零來實現,如下面修改後的程式碼所示:
for { select { case todo := <-toDoList: if todo.depth > 0 && !visited[todo.url] { crawling++ visited[todo.url] = true go crawl(todo, fetcher, toDoList, doneCrawling) } case <-doneCrawling: crawling-- } if crawling == 0 { break } }
以上是為什麼帶 Goroutine 的 Go Select 語句會掛起,除非加入 Print 語句?的詳細內容。更多資訊請關注PHP中文網其他相關文章!