goroutine 的调度模型
MPG 模式基本介绍
- M:操作系统的主线程(是物理线程)
- P:协程执行需要的上下文环境
- G:协程
MPG 模式运行的状态 1
- 当前程序有三个M,如果三个M都在一个cpu运行,就是并发,如果在不同的cpu运行就是并行
- M1,M2,M3正在执行一个G,M1的协程队列有三个,M2的协程队列有3个,M3协程队列有2个
- 从上图可以看到:Go的协程是轻量级的线程,是逻辑态的,Go可以容易的起上万个协程。
- 其它程序c/java的多线程,往往是内核态的,比较重量级,几千个线程可能耗光cpu
MPG 模式运行的状态 2
- 分成两个部分来看
- 原来的情况是M0主线程正在执行G0协程,另外有三个协程在队列等待
- 如果G0协程阻塞,比如读取文件或者数据库
- 这时就会创建M1主线程(也可能是从已有的线程池中取出M1),并且将等待的3个协程挂到M1下开始执行,MO的主线程下的G0仍然执行文件io的读写。
- 这样的MPG调度模式,可以既让G0执行,同时也不会让队列的其它协程一直阻塞,仍然可以并发/并行执行。
- 等到G0不阻塞了,M0会被放到空闲的主线程继续执行(从已有的线程池中取),同时G0又会被唤醒。
设置运行CPU数目
- 为了充分了利用多 cpu 的优势,在 Golang 程序中,设置运行的 cpu 数目
- go1.8后,默认让程序运行在多个核上,可以不用设置了
- go1.8前,还是要设置一下,可以更高效的利益cpu
package runtime
import "runtime"
- runtime包提供和go运行时环境的互操作,如控制go程的函数。
- 它也包括用于reflect包的低层次类型信息;参见reflect报的文档获取运行时类型系统的可编程接口。
func NumCPU() int
func GOMAXPROCS(n int) int
- GOMAXPROCS设置可同时执行的最大CPU数,并返回先前的设置。
- 若 n < 1,它就不会更改当前设置。
- 本地机器的逻辑CPU数可通过 NumCPU 查询。本函数在调度程序优化后会去掉。
演示案例
package main
import (
"runtime"
"fmt"
)
func main() {
cpuNum := runtime.NumCPU()
fmt.Println("cpuNum=", cpuNum)
//可以自己设置使用多个cpu
runtime.GOMAXPROCS(cpuNum - 1)
fmt.Println("ok")
}