第一段
package main
import "fmt"
import "runtime"
func main() {
runtime.GOMAXPROCS(1)
for i :=0; i<10; i++ {
i := i
go func() {
fmt.Println("A:",i)
}()
}
var ch = make(chan int)
<- ch
}
输出结果
无论执行多少回,A: 9 一定是第一个输出的。后面就让我们来解释一下这是为什么吧。,
A: 9
A: 0
A: 1
A: 2
A: 3
A: 4
A: 5
A: 6
A: 7
A: 8
解析:
第一句代码: runtime.GOMAXPROCS(1) 设置全局只有一个P表示将goroutine的并行调整至1。同时在只有一个P的时候所有创建的
goroutine都要进入三个队列中(runnext,local,gobal)。
第二句代码: for 开启一个循环10次的代码。
第三句代码: i := i 这里是因为for循环的时候i是一个指针,如果循环内的代码使用for 语句的i,那么所有的goroutine拿到的I都将是9,即i最后一次循环的值。
第四句代码: go func(){} 开启一个goroutine
第五句代码: fmt.Println() goroutine的执行内容是打印A: i
第六句代码: var ch = make(chan int) 创建一个没有缓冲的chan
第七句代码: <- ch 读取一个没有缓冲,如果chan没有信息,则会阻塞,这里用途就是阻塞main()进程
程序执行过程 :
- 先将P设置为1,在GMP调度模型中P只有一个的话,所有的goroutine都将进入队列(三个队列)。
- golang 开一个goroutine的话,都会将goroutine放置在runnext队列,runnext有goroutine的话,会将已有的goroutine放置到local队列中,并将新的goroutine放置到runnext。 即循环开启10个goroutine的话最后一个将在runnext,将会优先执行。这里最后一个goroutine中的i是9,于是9就会最先打印出来
- 执行完runnext会从local队列的头部开始执行goroutine
第二段
package main
import "time"
import "fmt"
import "runtime"
func main() {
runtime.GOMAXPROCS(1)
for i :=0; i<10; i++ {
i := i
go func() {
fmt.Println("A:",i)
}()
}
time.Sleep(time.Hour)
}
1.13 输出结果
A: 0
A: 1
A: 2
A: 3
A: 4
A: 5
A: 6
A: 7
A: 8
A: 9
1.14输出结果
A: 9
A: 0
A: 1
A: 2
A: 3
A: 4
A: 5
A: 6
A: 7
A: 8
解析:
第一句代码: runtime.GOMAXPROCS(1) 设置全局只有一个P表示将goroutine的并行调整至1。同时在只有一个P的时候所有创建的
goroutine都要进入三个队列中(runnext,local,gobal)。
第二句代码: for 开启一个循环10次的代码。
第三句代码: i := i 这里是因为for循环的时候i是一个指针,如果循环内的代码使用for 语句的i,那么所有的goroutine拿到的I都将是9,即i最后一次循环的值。
第四句代码: go func(){} 开启一个goroutine
第五句代码: fmt.Println() goroutine的执行内容是打印A: i
第六句代码: time.Sleep(time.Hour) 将程序暂停1小时. 这里注意1.13和1.14的go版本中 time的实现有点不同。 1.13会创建一个goroutine,1.14则不会
程序执行过程 :
- 先将P设置为1,在GMP调度模型中P只有一个的话,所有的goroutine都将进入队列(三个队列)。
- golang 开一个goroutine的话,都会将goroutine放置在runnext队列,runnext有goroutine的话,会将已有的goroutine放置到local队列中,并将新的goroutine放置到runnext。 即循环开启10个goroutine的话最后一个将在runnext,将会优先执行。
- 此时执行到time.Sleep(time.Hour),在1.13之前 time的实现会另外创建一个goroutine,于是这个goroutine会被最优先执行。之后再从local队列中从开头取。