golang调度器原理
三个常见的线程模型。
一个是N:1的,即多个用户空间线程运行在一个OS线程上。这个模型可以很快的进行上下文切换,但是不能利用多核系统(multi-core systems)的优势。
一个是1:1的,即可执行程序的一个线程匹配一个OS线程。这个模型能够利用机器上的所有核心的优势,但是上下文切换非常慢,因为它不得不陷入OS(trap through the OS)。
Go试图通过M:N的调度器去获取上述二者的全部优势。它在任意数目的OS线程上调用任意数目的goroutines。可以快速进行上下文切换,并且还能利用你系统上所有的核心的优势。这个模型主要的缺点是它增加了调度器的复杂性。
1 创建一个goroutine后,即生成一个G,会先找到一个P的本地队列,如果没满,则放入等待,若满了,就会取该P本地队列的一半和这个G放入全局队列等待,执行G的时候,若发生阻塞/非阻塞系统调用,则P会与当前的M解绑去寻找其它的M,当P的本地队列没有G时,M会进入自旋,等待运行G,这时P会从全局队列至少取一个G,n = min(len(GQ)/GOMAXPROCS + 1, len(GQ/2)),若全局队列也没有G,则会从其它的P里steal一半的G过来,
用户调度器实现用户线程到 KSE 的『调度』,内核调度器实现 KSE 到 CPU 上的『调度』
参考:https://strikefreedom.top/high-performance-implementation-of-goroutine-pool#b3_solo_h2_6
https://learnku.com/articles/41728
https://draveness.me/golang/docs/part3-runtime/ch06-concurrency/golang-goroutine/
https://www.cnblogs.com/sunsky303/p/9705727.html
https://www.jianshu.com/p/122c5b53e454