真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Go語(yǔ)言defer語(yǔ)句的三種機(jī)制整理-創(chuàng)新互聯(lián)

Golang 的 1.13 版本 與 1.14 版本對(duì) defer 進(jìn)行了兩次優(yōu)化,使得 defer 的性能開銷在大部分場(chǎng)景下都得到大幅降低,其中到底經(jīng)歷了什么原理?

員工經(jīng)過(guò)長(zhǎng)期磨合與沉淀,具備了協(xié)作精神,得以通過(guò)團(tuán)隊(duì)的力量開發(fā)出優(yōu)質(zhì)的產(chǎn)品。創(chuàng)新互聯(lián)堅(jiān)持“專注、創(chuàng)新、易用”的產(chǎn)品理念,因?yàn)椤皩W⑺詫I(yè)、創(chuàng)新互聯(lián)網(wǎng)站所以易用所以簡(jiǎn)單”。公司專注于為企業(yè)提供成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、微信公眾號(hào)開發(fā)、電商網(wǎng)站開發(fā),微信小程序定制開發(fā),軟件按需網(wǎng)站建設(shè)等一站式互聯(lián)網(wǎng)企業(yè)服務(wù)。

這是因?yàn)檫@兩個(gè)版本對(duì) defer 各加入了一項(xiàng)新的機(jī)制,使得 defer 語(yǔ)句在編譯時(shí),編譯器會(huì)根據(jù)不同版本與情況,對(duì)每個(gè) defer 選擇不同的機(jī)制,以更輕量的方式運(yùn)行調(diào)用。

堆上分配

在 Golang 1.13 之前的版本中,所有 defer 都是在堆上分配,該機(jī)制在編譯時(shí)會(huì)進(jìn)行兩個(gè)步驟:

  1. 在 defer 語(yǔ)句的位置插入 runtime.deferproc,當(dāng)被執(zhí)行時(shí),延遲調(diào)用會(huì)被保存為一個(gè) _defer 記錄,并將被延遲調(diào)用的入口地址及其參數(shù)復(fù)制保存,存入 Goroutine 的調(diào)用鏈表中。
  2. 在函數(shù)返回之前的位置插入 runtime.deferreturn,當(dāng)被執(zhí)行時(shí),會(huì)將延遲調(diào)用從 Goroutine 鏈表中取出并執(zhí)行,多個(gè)延遲調(diào)用則以 jmpdefer 尾遞歸調(diào)用方式連續(xù)執(zhí)行。

這種機(jī)制的主要性能問(wèn)題存在于每個(gè) defer 語(yǔ)句產(chǎn)生記錄時(shí)的內(nèi)存分配,以及記錄參數(shù)和完成調(diào)用時(shí)參數(shù)移動(dòng)的系統(tǒng)調(diào)用開銷。

棧上分配

Go 1.13 版本新加入 deferprocStack 實(shí)現(xiàn)了在棧上分配的形式來(lái)取代 deferproc,相比后者,棧上分配在函數(shù)返回后 _defer 便得到釋放,省去了內(nèi)存分配時(shí)產(chǎn)生的性能開銷,只需適當(dāng)維護(hù) _defer 的鏈表即可。

編譯器有自己的邏輯去選擇使用 deferproc 還是 deferprocStack,大部分情況下都會(huì)使用后者,性能會(huì)提升約 30%。不過(guò)在 defer 語(yǔ)句出現(xiàn)在了循環(huán)語(yǔ)句里,或者無(wú)法執(zhí)行更高階的編譯器優(yōu)化時(shí),亦或者同一個(gè)函數(shù)中使用了過(guò)多的 defer 時(shí),依然會(huì)使用 deferproc。

開放編碼

Go 1.14 版本繼續(xù)加入了開發(fā)編碼(open coded),該機(jī)制會(huì)將延遲調(diào)用直接插入函數(shù)返回之前,省去了運(yùn)行時(shí)的 deferproc 或 deferprocStack 操作,在運(yùn)行時(shí)的 deferreturn 也不會(huì)進(jìn)行尾遞歸調(diào)用,而是直接在一個(gè)循環(huán)中遍歷所有延遲函數(shù)執(zhí)行。

這種機(jī)制使得 defer 的開銷幾乎可以忽略,唯一的運(yùn)行時(shí)成本就是存儲(chǔ)參與延遲調(diào)用的相關(guān)信息,不過(guò)使用此機(jī)制需要一些條件:

  1. 沒(méi)有禁用編譯器優(yōu)化,即沒(méi)有設(shè)置 -gcflags "-N";
  2. 函數(shù)內(nèi) defer 的數(shù)量不超過(guò) 8 個(gè),且返回語(yǔ)句與延遲語(yǔ)句個(gè)數(shù)的乘積不超過(guò) 15;
  3. defer 不是在循環(huán)語(yǔ)句中。

該機(jī)制還引入了一種元素 —— 延遲比特(defer bit),用于運(yùn)行時(shí)記錄每個(gè) defer 是否被執(zhí)行(尤其是在條件判斷分支中的 defer),從而便于判斷最后的延遲調(diào)用該執(zhí)行哪些函數(shù)。

延遲比特的原理:

同一個(gè)函數(shù)內(nèi)每出現(xiàn)一個(gè) defer 都會(huì)為其分配 1 個(gè)比特,如果被執(zhí)行到則設(shè)為 1,否則設(shè)為 0,當(dāng)?shù)竭_(dá)函數(shù)返回之前需要判斷延遲調(diào)用時(shí),則用掩碼判斷每個(gè)位置的比特,若為 1 則調(diào)用延遲函數(shù),否則跳過(guò)。

為了輕量,官方將延遲比特限制為 1 個(gè)字節(jié),即 8 個(gè)比特,這就是為什么不能超過(guò) 8 個(gè) defer 的原因,若超過(guò)依然會(huì)選擇堆棧分配,但顯然大部分情況不會(huì)超過(guò) 8 個(gè)。

用代碼演示如下:

deferBits = 0 // 延遲比特初始值 00000000

deferBits |= 1<<0 // 執(zhí)行第一個(gè) defer,設(shè)置為 00000001
_f1 = f1 // 延遲函數(shù)
_a1 = a1 // 延遲函數(shù)的參數(shù)
if cond {
  // 如果第二個(gè) defer 被執(zhí)行,則設(shè)置為 00000011,否則依然為 00000001
  deferBits |= 1<<1
  _f2 = f2
  _a2 = a2
}
...
exit:
// 函數(shù)返回之前,倒序檢查延遲比特,通過(guò)掩碼逐位進(jìn)行與運(yùn)算,來(lái)判斷是否調(diào)用函數(shù)

// 假如 deferBits 為 00000011,則 00000011 & 00000010 != 0,因此調(diào)用 f2
// 否則 00000001 & 00000010 == 0,不調(diào)用 f2
if deferBits & 1<<1 != 0 {
  deferBits &^= 1<<1 // 移位為下次判斷準(zhǔn)備
  _f2(_a2)
}
// 同理,由于 00000001 & 00000001 != 0,調(diào)用 f1
if deferBits && 1<<0 != 0 {
  deferBits &^= 1<<0
  _f1(_a1)
}

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。


網(wǎng)站標(biāo)題:Go語(yǔ)言defer語(yǔ)句的三種機(jī)制整理-創(chuàng)新互聯(lián)
分享鏈接:http://weahome.cn/article/djpoch.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部