gmp模型:
gmp是调度层面的实现, 包含4个结构, 分别是g, m, p, sched
g(goroutine):代表go协程goroutine, 存储了goroutine的执行栈信息,
Goroutine状态以及Goroutine的任务函数等, G的数量无限制,
理论上只受内存影响, 创建一个G的初始栈大小为2-4K, 配置一般机器
也能开启数十万个Goroutine, 而且go语言在G退出的时候, 还会把G清理
之后放到P本地或者全局的闲置列表中。
M(machine):go对操作系统线程的封装, 可以看做是操作系统内核线程,
想要在cpu上执行代码必须有线程, 通过系统调用clone创建, M在绑定有效
p之后,进行循环调度, 而循环调度的机制大致是从p的本地运行队列以及全局
队列中获取G, 切换到G的执行栈上执行G的函数,
调用goexit做清理工作并回到M, 如此反复。
M并不保留G状态, 这是G可以跨M调度的基础, M数量有限制,
默认数量是10000, 可以通过debug.SetMaxThreads()来进行设置,
如果M空闲, 那么就会回收或者睡眠。
P(processor):虚拟处理器, M执行G所需要的资源和上下文,