• 为什么用户实现协程
    • POSIX线程模型累赘
      • 进程/线程 切换开销大
      • 空间资源占用大
    • os调度对go模型不合理
      • go gc需要内存处理一致状态(所有线程停止), os调度时,因gc时间不确定,期间大量线程停止工作
        • go调度器知道什么时候内存处于一致性状态(只需正在核上运行线程)
  • 本质
    • 用户态,寄存器+栈, 让出(协作而非抢占)
  • 调度方式(线程模型)
    • N:1 # N个用户空间线程运行在1个内核空间线程
      • 上下文切换快
      • 无法利用多核
    • 1:1
      • POSIX(pthread), java
      • 利用多核
      • 上下文切换慢,每次调度都在用户态和内核态间切换
    • M:N
      • 任意内核模型管理任意goroutine
      • 调度复杂性大
  • go
    • M(machine)代表内核线程
    • G(goroutine)有自己的栈,程序计数器,调度信息(如正阻塞的channel)
    • P(processor)调度上下文, $GOMAXPROCS设置数量
    • P中有G队列(runqueue, 队尾添加新G)
      • 当前运行一个G, 到调度点时,队列弹出另一个G
      • P周期检查全局G队列防止其中G饿死
      • P运行完,全局G队列拉取G
      • P运行完,全局G队列空,从其它P拉取一半G
    • P运行在M, M阻塞时P移到其它M, 阻塞M中保留阻塞的G
    • 调度器创建足够多M跑P
      • 阻塞M中G的syscall返回, M尝试偷一个P
      • 没得到P时, 它的G加入全局G队列, M进线池睡眠