一文了解Golang的关键字go

446 阅读1分钟

使用 go 关键字可以开启一个新的 goroutine 去运行函数

但是go关键字的调用协议与普通函数的调用协议是不同的,如果新的 goroutine 与当前 goroutine 共用一个栈,会导致相互覆盖

正常的函数调用

    MOVL    $1, 0(SP)
    MOVL    $2, 4(SP)
    MOVL    $3, 8(SP)
CALL    f(SB)

go f(1, 2, 3) 调用

    MOVL    $1, 0(SP)
    MOVL    $2, 4(SP)
    MOVL    $3, 8(SP)
    PUSHQ   $f(SB)
    PUSHQ   $12
    CALL    runtime.newproc(SB)
    POPQ    AX
    POPQ    AX

并没有直接CALL调用函数f,而是将12与函数f的入口地址压栈,然后调用函数runtime.newproc

12是参数占用大小,runtime.newproc函数接受的参数分别是参数大小,新的 goroutine 要运行的函数,函数的n个参数TODO现在源码好像是没有最后这个args的

在runtime.newproc中,会新建一个栈空间,将栈参数的12个字节拷贝到新的栈空间并让栈指针指向参数。

这时的线程状态像被调度器剥夺cpu后一样,寄存器都保存在类似pcb中的一个结构体struct G中,f被保存在struct G的entry域,后面调度器恢复 goroutine 后,新线程从f开始

可以说,go关键字的实现只是一个语法糖衣

go f(args)

等同于

runtime.newproc(size, f, args)