下面的代碼會輸出什麼,並說明原因:
//代碼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