91在线观看视频-91在线观看视频-91在线观看免费视频-91在线观看免费-欧美第二页-欧美第1页

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

初探Golang內聯

Linux愛好者 ? 來源:稀土掘金技術社區 ? 作者:ag9920 ? 2022-12-13 09:51 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

開篇

今天我們來聊聊 Golang 中的內聯。

我們知道,函數調用本身是存在成本的。如果把一個實際調用的函數產生的指令,直接插入到的位置,來替換對應的函數調用指令。就可以消除掉這部分性能損耗。但同時也要注意,我們需要維護各個模塊的可讀性,需要保證高內聚,低耦合,不可能把所有邏輯合到一個函數,這樣可讀性大大降低。

那么,既然在代碼層面做不太好,還有沒有別的招呢?

內聯就是來做這件事的。下面我們一起來看一下。

內聯

所謂內聯,指的是編譯期間,直接將調用函數的地方替換為函數的實現,它可以減少函數調用的開銷以提高程序的性能。內聯函數是直接復制“鑲嵌”到主函數中去的,就是將內聯函數的代碼直接放在內聯函數的位置上,

這與一般函數不同,主函數在調用一般函數的時候,是指令跳轉到被調用函數的入口地址,執行完被調用函數后,指令再跳轉回主函數上繼續執行后面的代碼;而由于內聯函數是將函數的代碼直接放在了函數的位置上,所以沒有指令跳轉,指令按順序執行。Go程序編譯時,默認將進行內聯優化。

當然,內聯也并不是沒有代價,這本質是一種以空間換時間的優化方法,其帶來的優點是使CPU需要執行的指令數變少了,不需要根據地址跳轉的過程了,不用壓棧和出棧的過程了,我們把可以復用的程序指令在調用它的地方完全展開了。如果一個函數在很多地方都被調用了,那么就會展開很多次,整個程序占用的空間就會變大了。

需要注意,內聯也是有門檻的,并不是隨便一個函數調用都可以原地替換。Golang 編譯器內部會有一套自己的判斷規則,判斷一次函數調用能否被內聯,后面的章節我們會提到。這也是為什么我們會說:

Inlining is the act of combining smaller functions into their respective callers.

這個 small 的程度很關鍵。

簡單小結一下,內聯帶來的好處有兩個:

解除函數調用的開銷,以空間換時間;

支持編譯器更有效地應用其他優化策略。

函數調用開銷

一個goroutine會有一個單獨的棧,棧又會包含多個棧幀,棧幀是函數調用時在棧上為函數所分配的區域。函數調用存在一些固定開銷:

創建棧幀;

讀寫寄存器

棧溢出檢測。

內聯什么時候最有效

函數執行的開銷 vs 函數調用的開銷。這兩個開銷的比值會很大程度上決定【內聯】的效果。

內聯其實就是把函數調用這份固定開銷給消除了,所以尤其對于函數體極其簡單的函數有效果。如果你的函數執行了一系列復雜邏輯,開銷遠超【函數調用】本身,這里的優化就微不足道了。

內聯雖然可以減少函數調用的開銷,但是也可能因為存在重復代碼,從而導致 CPU 緩存命中率降低,所以并不能盲目追求過度的內聯,需要結合 profile 結果來具體分析。

Golang 編譯器對內聯的要求

參考官方 wiki:github.com/golang/go/w…[1]

a2e89d80-77b3-11ed-8abf-dac502259ad0.jpg

想要內聯,方法本身必須滿足以下條件:

函數足夠簡單,當解析AST時,Go申請了80個節點作為內聯的預算。每個節點都會消耗一個預算。函數的開銷不能超過這個預算;

不能包含閉包,defer,recover,select;

不能以 go:noinline 或 go:unitptrescapes 開頭;

必須有函數體;

其他等復雜要求,詳細可見src/cmd/compile/internal/gc/inl.go相關內容。我們可以使用 gcflags 參數來判斷能不能內聯。

內聯的實現原理建議大家看看這篇文章:gocompiler.shizhz.me/8.-golang-b…[2]

如何禁止內聯

單個函數級別:在函數定義前一行添加//go:noinline;

全局編譯級別:可通過-gcflags="-l"選項全局禁用內聯,與一個-l禁用內聯相反,如果傳遞兩個或兩個以上的-l則會打開內聯,并啟用更激進的內聯策略。

gcflags

go build 時可以使用 -gcflags 指定編譯選項,-gcflags 參數的格式是:

-gcflags="pattern=arg list"

pattern 是選擇包的模式,arg list 是空格分割的編譯選項,如果編譯選項中含有空格,可以使用引號包起來。

如:-gcflags="all=-N -l" 代表的是表示主模塊和它所有的依賴都禁用【編譯器優化】和【內聯】。更多編譯選項參照 go tool compile --help

Use -gcflags -m to observe the result of escape analysis and inlining decisions for the gc toolchain.

使用 go build 編譯時,我們可以使用參數-gflags="-m"運行,可顯示被內聯的函數,使用運行參數-gflags="-m -m"可以看到原因。類似:

./main.go:14:6:cannotinlinexxx:unhandledopXXX

/ins.go:9:6:cannotinlinexxx:functiontoocomplex:cost104exceedsbudget80

我們可以用下面的命令分析變量是否逃逸:

gorun-gcflags'-m-l'main.go

-m 其實是打印優化策略的語義,實際上最多總共可以用 4 個 -m,但是信息量較大,一般用 1 個就可以了;

-l 會禁用函數內聯,在這里禁用掉內聯能更好的觀察逃逸情況,減少干擾

內聯后堆棧信息還對不對

內聯會將函數調用的過程抹掉,這會引入一個新的問題:代碼的堆棧信息還能否保證。其實這一點不用擔心,Golang 內部會為每個存在內聯優化的 goroutine 維持一個內聯樹(inlining tree),該樹可通過 -gcflags="-d pctab=pctoinline" 命令查看,Go在生成的代碼中映射了內聯函數。并且,也映射了行號。這張表被嵌入到了二進制文件中,所以在運行時可以得到準確的堆棧信息。

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 寄存器
    +關注

    關注

    31

    文章

    5439

    瀏覽量

    124925
  • 函數
    +關注

    關注

    3

    文章

    4384

    瀏覽量

    65113
  • 編譯器
    +關注

    關注

    1

    文章

    1663

    瀏覽量

    50337

原文標題:初探 Golang 內聯

文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    Golang接口的作用和應用場景

    Golang(Go)作為一門現代的靜態類型編程語言,提供了許多強大的特性,其中之一便是接口(interface)。接口是Golang中的一個核心概念,它具有廣泛的應用場景,可以幫助開發者實現
    的頭像 發表于 12-05 10:44 ?1464次閱讀

    如何使用Golang連接MySQL

    首先我們來看如何使用Golang連接MySQL。
    的頭像 發表于 01-08 09:42 ?3923次閱讀
    如何使用<b class='flag-5'>Golang</b>連接MySQL

    Golang怎么實現UTS隔離

    Golang實現UTS隔離
    發表于 08-23 14:44

    基于SUIF的函數內聯技術

    從基于調用圖的函數內聯技術、函數參數的映射技術和內聯使用的不同策略3 個方面討論基于SUIF 系統的內聯技術的實現。根據KAP 系統需求,提出葉節點的內聯算法,以滿足并行性分
    發表于 03-28 09:50 ?6次下載

    C++如何處理內聯虛函數

    當一個函數是內聯和虛函數時,會發生代碼替換或使用虛表調用嗎? 為了弄 清楚內聯和虛函數,讓我們將它們分開來考慮。通常,一個內聯函數是被展開的 。 class CFoo {
    發表于 11-29 11:59 ?28次下載

    內聯函數詳解

    什么是內聯性和外聯函數 類的成員函數可以分為內聯函數和外聯函數。內聯函數是指那些定義在類體內的成員函數,即該函數的函數體放在類體內。而說明在類體內,定義在類體外的成員函數叫外聯函數。外聯函數的函數體
    發表于 11-02 14:05 ?0次下載

    內聯函數和外聯函數有什么區別

    內聯函數是指用inline關鍵字修飾的函數。在類內定義的函數被默認成內聯函數。內聯函數從源代碼層看,有函數的結構,而在編譯后,卻不具備函數的性質。內聯函數不是在調用時發生控制轉移,而是
    發表于 12-15 11:52 ?6294次閱讀
    <b class='flag-5'>內聯</b>函數和外聯函數有什么區別

    使用golang channel的諸多特性和技巧

    ? 本文介紹了使用 golang channel 的諸多特性和技巧,已經熟悉了 go 語言特性的小伙伴也可以看看,很有啟發。
    的頭像 發表于 09-06 15:14 ?2159次閱讀
    使用<b class='flag-5'>golang</b> channel的諸多特性和技巧

    C++基礎語法之inline 內聯函數

    上節我們分析了C++基礎語法的const,static以及 this 指針,那么這節內容我們來看一下 inline 內聯函數吧! inline 內聯函數 特征 相當于把內聯函數里面的內容寫在調用
    的頭像 發表于 09-09 09:38 ?2435次閱讀

    GoLang的安裝和使用

    GoLang的安裝和使用
    的頭像 發表于 01-13 14:06 ?1544次閱讀
    <b class='flag-5'>GoLang</b>的安裝和使用

    講解下C語言的內聯函數

    內聯函數是C語言從C++中借鑒過來的,適當的使用內聯函數可以提高程序的執行效率。
    的頭像 發表于 02-16 09:15 ?1852次閱讀

    C語言內聯函數,提升C技巧必備

    內聯函數是C語言從C++中借鑒過來的,適當的使用內聯函數可以提高程序的執行效率。本篇文章就來講解下內聯函數,趕緊來看下吧!
    的頭像 發表于 02-16 09:16 ?1059次閱讀

    一個快速應用程序開發(RAD)工具(Golang版)

    SNMPAgent Builder(Golang版)是一個快速應用程序開發(RAD)工具,用于基于Golang 的 SNMP代理開發。提供了一個直觀的圖形用戶界面,用于自動執行各種SNMP 代理開發任務
    的頭像 發表于 04-13 09:30 ?1848次閱讀

    【芒果派MangoPi MQ Quad】使用Golang點燈

    使用Golang在芒果派上點燈
    的頭像 發表于 07-21 14:44 ?1099次閱讀
    【芒果派MangoPi MQ Quad】使用<b class='flag-5'>Golang</b>點燈

    宏的缺陷與內聯函數的引入

    。 所以為了解決這種不利于調試的問題,就有了內聯函數。 那么什么是內聯函數呢? 我們以inline修飾的函數叫做內聯函數,編譯階段,C編譯器會在調用函數的地方直接把函數展開,沒有壓棧開銷,內聯
    的頭像 發表于 11-01 17:57 ?701次閱讀
    主站蜘蛛池模板: 狠狠色丁香婷婷久久综合不卡 | 美女黄页免费 | 夜夜艹| 天堂网在线www最新版在线 | 国产免费一区二区三区在线 | 日本毛片在线观看 | 国语一区 | 色婷婷色99国产综合精品 | 最新版天堂资源官网 | 69er小视频 | 中文字幕在线第一页 | 直接观看黄网站免费视频 | 欧美高清a| 午夜视频在线 | 成人激情综合网 | 自拍偷拍综合网 | 午夜看片网址 | 韩国三级中文 | 被公侵犯肉体中文字幕一区二区 | 日本三级吹潮 | 天天做人人爱夜夜爽2020毛片 | 亚洲怡红院在线 | 国产91丝袜在线播放九色 | 丁香六月综合激情 | 伊人网视频 | 丁香婷婷综合五月六月 | 四虎影院在线视频 | 国产成人综合亚洲怡春院 | 四虎影院欧美 | 色惰网站| 欧美三级视频网站 | 久久精品国产福利 | 久久精品1 | 亚洲国产激情在线一区 | 在线一级毛片 | 午夜禁片 | 久久天天躁狠狠躁夜夜2020一 | dyav午夜片 | 人人添人人澡人人澡人人人爽 | 天天做天天爱天天爽综合区 | 午夜影视啪啪免费体验区深夜 |