Go語(yǔ)言 關(guān)鍵字:go

2018-07-25 17:23 更新

在Go語(yǔ)言中,表達(dá)式go f(x, y, z)會(huì)啟動(dòng)一個(gè)新的goroutine運(yùn)行函數(shù)f(x, y, z)。函數(shù)f,變量x、y、z的值是在原goroutine計(jì)算的,只有函數(shù)f的執(zhí)行是在新的goroutine中的。顯然,新的goroutine不能和當(dāng)前go線程用同一個(gè)棧,否則會(huì)相互覆蓋。所以對(duì)go關(guān)鍵字的調(diào)用協(xié)議與普通函數(shù)調(diào)用是不同的。

首先,讓我們看一下如果是C代碼新建一條線程的實(shí)現(xiàn)會(huì)是什么樣子的。大概會(huì)先建一個(gè)結(jié)構(gòu)體,結(jié)構(gòu)體里存f、x、y和z的值。然后寫一個(gè)help函數(shù),將這個(gè)結(jié)構(gòu)體指針作為輸入,函數(shù)體內(nèi)調(diào)用f(x, y, z)。接下來(lái),先填充結(jié)構(gòu)體,然后調(diào)用newThread(help, structptr)。其中help是剛剛那個(gè)函數(shù),它會(huì)調(diào)用f(x, y, z)。help函數(shù)將作為所有新建線程的入口函數(shù)。

這樣做有什么問題么?沒什么問題...只是這樣實(shí)現(xiàn)代價(jià)有點(diǎn)高,每次調(diào)用都會(huì)花上不少的指令。其實(shí)Go語(yǔ)言中對(duì)go關(guān)鍵字的實(shí)現(xiàn)會(huì)更加hack一些,避免了這么做。

先看看正常的函數(shù)調(diào)用,下面是調(diào)用f(1, 2, 3)時(shí)的匯編代碼:

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

首先將參數(shù)1、2、3進(jìn)棧,然后調(diào)用函數(shù)f。

下面是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

對(duì)比一個(gè)會(huì)發(fā)現(xiàn),前面部分跟普通函數(shù)調(diào)用是一樣的,將參數(shù)存儲(chǔ)在正常的位置,并沒有新建一個(gè)輔助的結(jié)構(gòu)體。接下來(lái)的兩條指令有些不同,將f和12作為參數(shù)進(jìn)棧而不直接調(diào)用f,然后調(diào)用函數(shù)runtime.newproc。

12是參數(shù)占用的大小。runtime.newproc函數(shù)接受的參數(shù)分別是:參數(shù)大小,新的goroutine是要運(yùn)行的函數(shù),函數(shù)的n個(gè)參數(shù)。

runtime.newproc中,會(huì)新建一個(gè)??臻g,將棧參數(shù)的12個(gè)字節(jié)拷貝到新??臻g中并讓棧指針指向參數(shù)。這時(shí)的線程狀態(tài)有點(diǎn)像當(dāng)被調(diào)度器剝奪CPU后一樣,寄存器PC、SP會(huì)被保存到類似于進(jìn)程控制塊的一個(gè)結(jié)構(gòu)體struct G內(nèi)。f被存放在了struct G的entry域,后面進(jìn)行調(diào)度器恢復(fù)goroutine的運(yùn)行,新線程將從f開始執(zhí)行。

和前面說的如果用C實(shí)現(xiàn)的差別就在于,沒有使用輔助的結(jié)構(gòu)體,而runtime.newproc實(shí)際上就是help函數(shù)。在函數(shù)協(xié)議上,go表達(dá)式調(diào)用就比普通的函數(shù)調(diào)用多四條指令而已,并且在實(shí)際上并沒有為go關(guān)鍵字設(shè)計(jì)一套特殊的東西。不得不說這個(gè)做法真的非常精妙!

總結(jié)一個(gè),go關(guān)鍵字的實(shí)現(xiàn)僅僅是一個(gè)語(yǔ)法糖衣而已,也就是:

    go f(args)

可以看作

    runtime.newproc(size, f, args)

links


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)