goroutine运行在用户态,是由runtime来控制调度的,调度过程中主要涉及到三个对象:G-go关键字启动的协程(也有内部启动的协程如g0)、M-运行G的系统线程(由操作系统控制调度)、P-资源处理器,用来管理G的,M必须绑定一个P才能运行其协程队列里的G。具体的调度过程是这样的:
程序启动时创建GOMAXPROCS个P,当有go关键字创建G时会优先加入到当前P的本地队列中(缓存局部性原理),当本地队列满了调度器会调度部分协程到全局队列中,此时P去线程池唤醒一个休眠的M(如没有则新创建一个M)进行绑定,M获取到P本地队列中的G开始执行,当本地队列里面的G执行完则先去全局队列获取,若获取不到则去其它队列偷取,若都没有则当前M进入自旋状态(因为线程的创建销毁唤醒比较消耗CPU,但是自旋线程本质是线程在运行不过没有执行G,因此也有数量限制,超过限制M休眠),不断的循环寻找等待新的G。