具体详细的内容可以看 小徐先生的编程世界 ,讲的非常好,也非常详细。

记录一点个人心得:

  • m本质上就是操作系统内核级的一个线程,协程的出现是为了减少线程频繁切换的开销,让多个协程并发的在一个线程中运行(因为用户态切换开销小)。但是协程如果出现阻塞,就会导致该线程直接阻塞,该线程内的其他协程无法运行。所以goroutine就加了一层p,成功将协程与线程进行了解藕,使得这种情况下,当一个协程阻塞的时候,可以把剩下的协程都切换到下一个线程中运行。

    谁和谁解耦 无 P 有 P
    G 和 M 多个G 必须绑定在某个 M 上,M 死了 G 也得陪葬。 G 绑定在 P 上。只要 P 能动,G 就能动,不在乎下面垫着的 M 是谁。
    M 和 资源 资源(队列/内存)绑在 M 身上。 资源绑在 P 身上。M 就像个“共享单车骑手”,随骑随走,车(P)坏了换一辆,人(M)累了换个人骑。
  • 每一个m都有一个g0作为调度者,去切换在该m上的协程。

  • 被动唤醒和正常新建(为了性能)优先进本地队列插队,而主动让出和超时抢占(为了公平)则必须去全局队列排队。每61次的从全局队列队首拉取一个直接执行。

  • 当一个g1在m1执行了很久的系统调用(比如读一个大文件),终于回来了。 但是此时,原来的 P1 已经被 sysmon 抢走给 M2 用了。此时如果有空闲的p,m1会拉一个p来执行g1,如果没有则会把g1放到全局队列中去。