Goroutine
将一个线程分为用户线程与内核线程(两者相互绑定),然后内核只用看到内核线程,内核线程完成硬件任务,协程完成用户任务
如图可以看见cpu视角中将一个线程分为了用户空间的协程与内核空间的线程且两者之间一一对应,且Golang对协程的处理,将协程改为Goroutine,内存改为几kb,灵活调度可以常切换,这就支持了golang中的高并发特性。
早期调度器的处理(G是协程,m是线程)
早期中通过协程调度器对协程以及线程的资源进行管理,老调度器具有一定的缺点,
1 创建,销毁,调度G都需要每个M获取锁,这就造成了激烈的锁竞争 2 M转移G会造成额外的系统负载 3 系统调用导致频繁的线程阻塞和取消阻塞操作增加了系统开销
所以在golang调度中又做了调整,如下图所示
后期golang处理器(GMP模式)
processor包含每一个goroutine的资源,程序到达p队列后才可等待被执行
调度器的设计策略
1.复用线程 (work stealing机制:若本线程为空,从别的p队列中偷取协程完成)
(handoff机制:一旦一个协程阻塞,唤醒一个thread,将阻塞的线程与协程绑定,剩下的协程给下一线程绑定,M1与p分离,不工作,等待g1执行加入其他队列,g1不执行m1便睡眠或者销毁)
2.利用并行 使用GOMAXPROCE限定p的个数
3.抢占 如果时间到没完成,另一个协程便抢占绑定cpu
4.全局g队列 如果本线程空闲,且偷不到其他线程队列中协程则从全队列中寻找