深入淺出Golang關鍵字"go" 2
前文“Cgo%E2%80%9D%E9%81%87%E4%B8%8A%E2%80%9Cruntime%E2%80%9D/" target="_blank" rel="nofollow,noindex">深入淺出Golang關鍵字"go" ”最後留了幾個問題:
func main() { runtime.GOMAXPROCS(1) for i := 0; i < 10; i++ { go println(i) } runtime.Gosched() time.Sleep(time.Second) } runtime.Gosched() 這一行程式碼。 如果註釋掉結果會怎樣?? 如果把這一行換成 runtime.Goexit() 或者 os.Exit(0) 又會是如何呢??
如果有關注到這個問題並且自己嘗試過的朋友會發現:
- 如果把runtime.Gosched() 註釋掉,結果會是 0~9;
- 如果換成runtime.Goexit() ,結果會是先輸出 0~9,然後程式 panic;
- 如果是os.Exit(0) ,則什麼也不會輸出。
對於 0~9 的結果,很多人會奇怪,runtime.Gosched() 到底怎樣影響到結果的?而 runtime.Goexit() 與 runtime.Gosched() 之間又存在怎樣的區別呢?
runtime.Gosched() 主要做了一件事就是嘗試交出 P 操作許可權,等待其它 gorotine 執行完成後再繼續執行當前 gorotine,結合前文的next 位置,則輸出了 9 0~8 這樣的結果。
但是當把這一行註釋了,程式會卡在 time.Sleep 處,這時候 go 程式設計中的另一個東西出場了——sys monitor 執行緒,這是 go 語言設計中的唯一一個(主執行緒除外)獨立的執行緒。它的作用是監控 gorotine 狀態的。當主 goroutine 在 sleep 時,monitor 認為佔用時間不符合預期,它會把 P 讓出來,而自己則進入 P 的 gorotine 佇列等待。那麼問題來了,P 有 next 位置呀,所以這時候 main gorotine 就佔了 next 位置。從而導致輸出順序變成 0~9了。
Goexit() 與 Gosched() 唯一不同的地方則是它會丟棄此行程式碼後的所有堆疊,
並且如果丟棄的是 main gorotine 的話會 panic。結果也自然是輸出 0~9 然後 panic 了。
os.Exit() 自不必多說了。