go GMP调度模型

goroutine

go协程的本质是用户态的线程,相比于传统的内核态线程,在性能方面有更多优点

  • 协程的切换发生在用户态,不用切换到内核态,不用处理时钟中断,效率更高。
  • 协程栈空间更小(go支持协程栈的自动增长),一般在4KB左右。而线程栈一般在4MB左右。从而可以创建大量协程。

但是从程序员的角度来看,协程和线程用起来体验差不多。

GMP调度模型

  • G(goroutine):协程。
  • M(machine):实际跑任务的机器,对应一个线程。
  • P(processor):调度器,里面保存了运行队列,抽象地看相当于是一个处理器。

一个P绑定到一个M上,每个P都会维护一个本地的G队列,这样每次从队列中取出G时不用竞争。如果本地队列空了,那么就会去全局G队列取一些过来。

每当进行磁盘IO,网络IO,协程休眠时协程就会让出,被调度。

抢占式调度

  • 栈增长时调度:在go1.14之前就实现了,如果一个协程长时间占据CPU,那么在调用函数的时候执行编译器插入的runtime.morestack栈增长函数,里面会判断是否进行抢占式调度。
  • 基于信号的抢占式调度:go1.14新特性,对于恶意的抢占程序,比如死循环,上面的方式也无法抢占。于是基于操作系统信号机制,当协程长时间占据CPU,那么给对应的线程发送sigurg信号,在注册的信号处理函数里面实现协程的切换。

参考资料

posted @ 2023-02-16 23:04  HachikoT  阅读(64)  评论(0编辑  收藏  举报