暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Golang高级解读:g0

艳先生 2022-07-21
5084

g0是Go语言中一种特殊协程,每个M都拥有一个g0协程,主要负责当前M上用户协程的调度工作,在执行runtime.newm()
函数创建M时,会同时初始化g0协程。

g0协程执行时使用系统栈,每个线程从启动开始往下执行,都属于g0的工作范围,直到运行至runtime.gogo()
启动用户协程,g0的工作才算暂时告一段落。

如图所示,Go语言中的协程调度总是不断地经历着类似的循环,以runtime.Gosched()
让出调度的流程举例。

当M创建之后,会同时初始化g0,运行在不同的平台上时,程序兼容各平台特性,最终执行到runtime.mstart()
正式启动g0的调度逻辑,再经过runtime.mstart1()
进入到调度循环中,由runtime.gogo()
启动用户协程,在用户逻辑中执行runtime.Gosched()
让出执行权限,再经过runtime.mcall()
回到g0的工作范围(这条流程下,刚刚执行过的协程会被放到全局队列中)。

反复重用的栈帧

调度技术上,有不少细节的设计很有技巧,其中一个就是对于g0栈帧的管理。

g0采用的是无限递归的方式重复运行调度逻辑,正常的程序执行路径都是保存在栈内,按正常程序的编译结果,g0的协程栈会无限膨胀直到移除,因此Go语言对这里进行了一些优化,当执行到runtime.mstart1()
时,g0会提前计算出一份协程栈的地址数据,保存在g0的结构中。


    _g_.sched.pc = getcallerpc()
    _g_.sched.sp = getcallersp()

    当g0执行到runtime.gogo()
    切换至用户协程时,并不会将当前g0的栈帧保存起来,而当用户协程经过runtime.mcall()
    回到g0时,再次加载的还是最初在runtime.mstart1()
    中计算出来的栈地址数据,通过这种技巧,反复将栈顶指针重置,从而实现栈帧的重复使用。


      TEXT runtime·mcall<ABIInternal>(SB), NOSPLIT, $0-8
      MOVQ AX, DX DX = fn


      // save state in g->sched
      MOVQ 0(SP), BX // caller's PC
      MOVQ BX, (g_sched+gobuf_pc)(R14)
      LEAQ fn+0(FP), BX // caller's SP
      MOVQ BX, (g_sched+gobuf_sp)(R14)
      MOVQ BP, (g_sched+gobuf_bp)(R14)


      // switch to m->g0 & its stack, call fn
      MOVQ g_m(R14), BX
      MOVQ m_g0(BX), SI // SI = g.m.g0
      CMPQ SI, R14 // if g == m->g0 call badmcall
      JNE goodm
      JMP runtime·badmcall(SB)
      goodm:
      MOVQ R14, AX // AX (and arg 0) = g
      MOVQ SI, R14 // g = g.m.g0
      get_tls(CX) // Set G in TLS
      MOVQ R14, g(CX)
      MOVQ (g_sched+gobuf_sp)(R14), SP // sp = g0.sched.sp
      PUSHQ AX // open up space for fn's arg spill slot
      MOVQ 0(DX), R12
      CALL R12 // fn(g)
      POPQ AX
      JMP runtime·badmcall2(SB)
      RET

      优先提高并行度

      Worker角色的M被创建时,默认都需要再创建另一个新的M,直至没有空闲的p为止。

      这块的处理流程是每创建一个M,在执行调度时,如果当前M中spinning
      成员被标记为true
      ,则尝试创建另一个M,采用全局变量sched.nmspinning
      控制创建流程,实现M的顺序创建。


      文章转载自艳先生,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

      评论