前段時間在找工做,也遇到一些不錯的面試題,其中有一道很常見,記錄一下,裏面還有一點搞不明白的:面試
下面兩段程序的輸出是什麼?spa
第一段:code
func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { fmt.Println(i) wg.Done() }() } wg.Wait() }
第二段:blog
func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func(n int) { fmt.Println(n) wg.Done() }(i) } wg.Wait() }
不少面試題解析裏面說第一段的10個goroutine輸出所有是10,我對這個結論是一直持懷疑態度的,由於輸出什麼,取決於那個goroutine裏面代碼被執行時外層i循環到哪裏,經我實測,也符合我本身的想法。隊列
可是那天那個面試官很確定的說會所有輸出同樣的數,我忘記問他的理由是什麼了。ip
關於第二段程序,亂序輸出0-9,相信你們是沒有異議的。總計有10^10種可能。針對第二段程序,那位面試官接着問了一個我以爲挺有水平的問題:這10^10種輸出裏面,確定有一種是按順序0-9依次輸出的,能不能經過一些方法,讓這段程序的輸出順序固定下來?這個問題我一時還真的抓不到要點了。。。後來在面試官不斷的提點下,我纔想到面試官的考點,不由以爲這個面試官仍是頗有水平的。
第二段程序如何改動才能達到定序輸出的效果呢?咱們知道每一個goroutine生成後,在P的本地G隊列未滿的時候,是依次加入到P的本地G隊列裏的,若是隻有一個P可用,也就只有一個本地G隊列存在,那麼這些G的執行順序實際上是取決於P的G隊列的順序的,那麼答案也就出來了,咱們只要設置P的數量爲1,便可達到定序輸出的目的:it
func main() { runtime.GOMAXPROCS(1) var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func(n int) { fmt.Println(n) wg.Done() }(i) } wg.Wait() }
不過這裏我仍是有一點不明白的是,9爲何是第一個被輸出的?我猜大概是跟GMP調度有關的。目前還不明白,有知道的同窗能夠指點我一下,謝謝。class
以上若有錯誤,歡迎指出。cli