一道常常考的面试题

前段时间在找工做,也遇到一些不错的面试题,其中有一道很常见,记录一下,里面还有一点搞不明白的:面试

下面两段程序的输出是什么?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循环到哪里,经我实测,也符合我本身的想法。队列

clipboard.png

可是那天那个面试官很确定的说会所有输出同样的数,我忘记问他的理由是什么了。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()
}

clipboard.png
不过这里我仍是有一点不明白的是,9为何是第一个被输出的?我猜大概是跟GMP调度有关的。目前还不明白,有知道的同窗能够指点我一下,谢谢。class

以上若有错误,欢迎指出。cli

相关文章
相关标签/搜索