簡單圍觀一下有趣的 //go: 指令

image

原文地址:簡單圍觀一下有趣的 //go: 指令

前言

如果你平時有翻看源碼的習慣,你肯定會發現。咦,怎么有的方法上面總是寫著 //go: 這類指令呢。他們到底是干嘛用的?

今天我們一同揭開他們的面紗,我將簡單給你介紹一下,它們都負責些什么

go:linkname

//go:linkname localname importpath.name

該指令指示編譯器使用 importpath.name 作為源代碼中聲明為 localname 的變量或函數的目標文件符號名稱。但是由于這個偽指令,可以破壞類型系統和包模塊化。因此只有當引用了 safe 包的時候才可以使用

簡單來講,就是 importpath.namelocalname 的符號別名,編譯器實際上會調用 localname 。但前提是使用了 safe 包才能使用

案例

time/time.go

...
func now() (sec int64, nsec int32, mono int64)

runtime/timestub.go

import _ "unsafe" // for go:linkname

//go:linkname time_now time.now
func time_now() (sec int64, nsec int32, mono int64) {
    sec, nsec = walltime()
    return sec, nsec, nanotime() - startNano
}

在這個案例中可以看到 time.now,它并沒有具體的實現。如果你初看可能會懵逼。這時候建議你全局搜索一下源碼,你就會發現其實現在 runtime.time_now

配合先前的用法解釋,可得知在 runtime 包中,我們聲明了 time_now 方法是 time.now 的符號別名。并且在文件頭引入了 unsafe 達成前提條件

go:noescape

//go:noescape

該指令指定下一個有聲明但沒有主體(意味著實現有可能不是 Go)的函數,不允許編譯器對其做逃逸分析

一般情況下,該指令用于內存分配優化。因為編譯器默認會進行逃逸分析,會通過規則判定一個變量是分配到堆上還是棧上。但凡事有意外,一些函數雖然逃逸分析其是存放到堆上。但是對于我們來說,它是特別的。我們就可以使用 go:noescape 指令強制要求編譯器將其分配到函數棧上

案例

// memmove copies n bytes from "from" to "to".
// in memmove_*.s
//go:noescape
func memmove(to, from unsafe.Pointer, n uintptr)

我們觀察一下這個案例,它滿足了該指令的常見特性。如下:

  • memmove_*.s:只有聲明,沒有主體。其主體是由底層匯編實現的
  • memmove:函數功能,在棧上處理性能會更好

go:nosplit

//go:nosplit

該指令指定文件中聲明的下一個函數不得包含堆棧溢出檢查。簡單來講,就是這個函數跳過堆棧溢出的檢查

案例

//go:nosplit
func key32(p *uintptr) *uint32 {
    return (*uint32)(unsafe.Pointer(p))
}

go:nowritebarrierrec

//go:nowritebarrierrec

該指令表示編譯器遇到寫屏障時就會產生一個錯誤,并且允許遞歸。也就是這個函數調用的其他函數如果有寫屏障也會報錯。簡單來講,就是針對寫屏障的處理,防止其死循環

案例

//go:nowritebarrierrec
func gcFlushBgCredit(scanWork int64) {
    ...
}

go:yeswritebarrierrec

//go:yeswritebarrierrec

該指令與 go:nowritebarrierrec 相對,在標注 go:nowritebarrierrec 指令的函數上,遇到寫屏障會產生錯誤。而當編譯器遇到 go:yeswritebarrierrec 指令時將會停止

案例

//go:yeswritebarrierrec
func gchelper() {
    ...
}

go:noinline

該指令表示該函數禁止進行內聯

案例

//go:noinline
func unexportedPanicForTesting(b []byte, i int) byte {
    return b[i]
}

我們觀察一下這個案例,是直接通過索引取值,邏輯比較簡單。如果不加上 go:noinline 的話,就會出現編譯器對其進行內聯優化

顯然,內聯有好有壞。該指令就是提供這一特殊處理

go:norace

//go:norace

該指令表示禁止進行競態檢測。而另外一種常見的形式就是在啟動時執行 go run -race,能夠檢測應用程序中是否存在雙向的數據競爭。非常有用

案例

//go:norace
func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
    ...
}

go:notinheap

//go:notinheap

該指令常用于類型聲明,它表示這個類型不允許從 GC 堆上進行申請內存。在運行時中常用其來做較低層次的內部結構,避免調度器和內存分配中的寫屏障。能夠提高性能

案例

// notInHeap is off-heap memory allocated by a lower-level allocator
// like sysAlloc or persistentAlloc.
//
// In general, it's better to use real types marked as go:notinheap,
// but this serves as a generic type for situations where that isn't
// possible (like in the allocators).
//
//go:notinheap
type notInHeap struct{}

總結

在本文我們簡單介紹了一些常見的指令集,我建議僅供了解。一般我們是用不到的,因為你的瓶頸可能更多的在自身應用上

但是了解這一些,對你了解底層源碼和運行機制會更有幫助。如果想再深入些,可閱讀我給出的參考鏈接 :)

參考

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容