golang 面試題(二)閉包

下面的代碼會輸出什麼,並說明原因:

//代碼1


package main

import (
	"fmt"
	"runtime"
	"time"
)

func main() {
	//設置最大的可同時使用的 CPU 核數 爲1
	runtime.GOMAXPROCS(1)

	for i := 0; i < 10; i++ {
		go func() {
			fmt.Println("A:",i)
		}()
	}

	//主線程等待其他線程執行完畢
	time.Sleep(3 * time.Second)
}
//代碼2


package main

import (
	"fmt"
	"runtime"
	"time"
)

func main() {
	//設置最大的可同時使用的 CPU 核數 爲1
	runtime.GOMAXPROCS(1)

	for i := 0; i < 10; i++ {
		go func(i int) {
			fmt.Println("B:",i)
		}(i)
	}

	//主線程等待其他線程執行完畢
	time.Sleep(3 * time.Second)
}

代碼1執行結果:

代碼2執行結果:

代碼1:

    這種現象的原因在於閉包共享外部的變量i,注意到,每次調用go就會啓動一個goroutine,這需要一定時間;但是,啓動的goroutine與循環變量遞增不是在同一個goroutine,可以把i認爲處於主goroutine中。啓動一個goroutine的速度遠小於循環執行的速度,所以即使是第一個goroutine剛起啓動時,外層的循環也執行到了最後一步了。由於所有的goroutine共享i,而且這個i會在最後一個使用它的goroutine結束後被銷燬,所以最後的輸出結果都是最後一步的A:10。

代碼2:

    可以理解爲,函數參數的傳遞是瞬時的,而且是在一個goroutine執行之前就完成,所以此時執行的閉包存儲了當前i的狀態。

驗證:

//驗證代碼


package main

import (
	"fmt"
	"runtime"
	"time"
)

func main() {
	//設置最大的可同時使用的 CPU 核數 爲1
	runtime.GOMAXPROCS(1)

	for i := 0; i < 10; i++ {
		//每次進循環,都將讓出cpu,讓另一個線程執行完畢,再進行下次循環。
		runtime.Gosched()
		go func() {
			fmt.Println("A:",i)
			//輸出完畢後,將cpu讓出,可以不加,默認執行
			//runtime.Gosched()
		}()
	}

	//主線程等待其他線程執行完畢
	time.Sleep(3 * time.Second)
}

執行結果如下:

@參考鏈接,https://blog.csdn.net/qq_35976351/article/details/81986496

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章