導航:首頁 > 源碼編譯 > go編譯不讓cpu優化參數

go編譯不讓cpu優化參數

發布時間:2023-05-09 19:25:36

『壹』 Go 語言內存管理(三):逃逸分析

Go 語言較之 C 語言一個很大的優勢就是自帶 GC 功能,可 GC 並不是沒有代價的。寫 C 語言的時候,在一個函數內聲明的變數,在函數退出後會自動釋放掉,因為這些變數分配在棧上。如果你期望變數的數據可以在函數退出後仍然能被訪問,就需要調用 malloc 方法在堆上申請內存,如果程序不再需要這塊內存了,再調用 free 方法釋放掉。Go 語言不需要你主動調用 malloc 來分配堆空間,編譯器會自動分析,找出需要 malloc 的變數,使用堆內存。編譯器的這個分析過程就叫做逃逸分析。

所以你在一個函數中通過 dict := make(map[string]int) 創建一個 map 變數,其背後的數據是放在棧空間上還是堆空間上,是不一定的。這要看編譯器分析的結果。

可逃逸分析並不是百分百准確的,它有缺陷。有的時候你會發現有些變數其實在棧空間上分配完全沒問題的,但編譯後程序還是把這些數據放在了堆上。如果你了解 Go 語言編譯器逃逸分析的機制,在寫代碼的時候就可以有意識地繞開這些缺陷,使你的程序更高效。

Go 語言雖然在內存管理方面降低了編程門檻,即使你不了解堆棧也能正常開發,但如果你要在性能上較真的話,還是要掌握這些基礎知識。

這里不對堆內存和棧內存的區別做太多闡述。簡單來說就是, 棧分配廉價,堆分配昂貴。 棧空間會隨著一個函數的結束自動釋放,堆空間需要時間 GC 模塊不斷地跟蹤掃描回收。如果對這兩個概念有些迷糊,建議閱讀下面 2 個文章:

這里舉一個小例子,來對比下堆棧的差別:

stack 函數中的變數 i 在函數退出會自動釋放;而 heap 函數返回的是對變數 i 的引用,也就是說 heap() 退出後,表示變數 i 還要能被訪問,它會自動被分配到堆空間上。

他們編譯出來的代碼如下:

邏輯的復雜度不言而喻,從上面的匯編中可看到, heap() 函數調用了 runtime.newobject() 方法,它會調用 mallocgc 方法從 mcache 上申請內存,申請的內部邏輯前面文章已經講述過。堆內存分配不僅分配上邏輯比棧空間分配復雜,它最致命的是會帶來很大的管理成本,Go 語言要消耗很多的計算資源對其進行標記回收(也就是 GC 成本)。

Go 編輯器會自動幫我們找出需要進行動態分配的變數,它是在編譯時追蹤一個變數的生命周期,如果能確認一個數據只在函數空間內訪問,不會被外部使用,則使用棧空間,否則就要使用堆空間。

我們在 go build 編譯代碼時,可使用 -gcflags '-m' 參數來查看逃逸分析日誌。

以上面的兩個函數為例,編譯的日誌輸出是:

日誌中的 &i escapes to heap 表示該變數數據逃逸到了堆上。

需要使用堆空間,所以逃逸,這沒什麼可爭議的。但編譯器有時會將 不需要 使用堆空間的變數,也逃逸掉。這里是容易出現性能問題的大坑。網上有很多相關文章,列舉了一些導致逃逸情況,其實總結起來就一句話:

多級間接賦值容易導致逃逸

這里的多級間接指的是,對某個引用類對象中的引用類成員進行賦值。Go 語言中的引用類數據類型有 func , interface , slice , map , chan , *Type(指針) 。

記住公式 Data.Field = Value ,如果 Data , Field 都是引用類的數據類型,則會導致 Value 逃逸。這里的等號 = 不單單只賦值,也表示參數傳遞。

根據公式,我們假設一個變數 data 是以下幾種類型,相應的可以得出結論:

下面給出一些實際的例子:

如果變數值是一個函數,函數的參數又是引用類型,則傳遞給它的參數都會逃逸。

上例中 te 的類型是 func(*int) ,屬於引用類型,參數 *int 也是引用類型,則調用 te(&j) 形成了為 te 的參數(成員) *int 賦值的現象,即 te.i = &j 會導致逃逸。代碼中其他幾種調用都沒有形成 多級間接賦值 情況。
同理,如果函數的參數類型是 slice , map 或 interface{} 都會導致參數逃逸。

匿名函數的調用也是一樣的,它本質上也是一個函數變數。有興趣的可以自己測試一下。

只要使用了 Interface 類型(不是 interafce{} ),那麼賦值給它的變數一定會逃逸。因為 interfaceVariable.Method() 先是間接的定位到它的實際值,再調用實際值的同名方法,執行時實際值作為參數傳遞給方法。相當於 interfaceVariable.Method.this = realValue

向 channel 中發送數據,本質上就是為 channel 內部的成員賦值,就像給一個 slice 中的某一項賦值一樣。所以 chan *Type , chan map[Type]Type , chan []Type , chan interface{} 類型都會導致發送到 channel 中的數據逃逸。

這本來也是情理之中的,發送給 channel 的數據是要與其他函數分享的,為了保證發送過去的指針依然可用,只能使用堆分配。

可變參數如 func(arg ...string) 實際與 func(arg []string) 是一樣的,會增加一層訪問路徑。這也是 fmt.Sprintf 總是會使參數逃逸的原因。

例子非常多,這里不能一一列舉,我們只需要記住分析方法就好,即,2 級或更多級的訪問賦值會 容易 導致數據逃逸。這里加上 容易 二字是因為隨著語言的發展,相信這些問題會被慢慢解決,但現階段,這個可以作為我們分析逃逸現象的依據。

下面代碼中包含 2 種很常規的寫法,但他們卻有著很大的性能差距,建議自己想下為什麼。

Benchmark 和 pprof 給出的結果:

熟悉堆棧概念可以讓我們更容易看透 Go 程序的性能問題,並進行優化。

多級間接賦值會導致 Go 編譯器出現不必要的逃逸,在一些情況下可能我們只需要修改一下數據結構就會使性能有大幅提升。這也是很多人不推薦在 Go 中使用指針的原因,因為它會增加一級訪問路徑,而 map , slice , interface{} 等類型是不可避免要用到的,為了減少不必要的逃逸,只能拿指針開刀了。

大多數情況下,性能優化都會為程序帶來一定的復雜度。建議實際項目中還是怎麼方便怎麼寫,功能完成後通過性能分析找到瓶頸所在,再對局部進行優化。

『貳』 go編譯so無法使用

1、首先,檢查動態庫文件嫌滾燃是否正確安裝,其次,檢查編譯選項是否正確,比如-shared參數是否被備殲正確設置。
2、最後,追蹤運行時出現的導致載入失敗芹虛的錯誤,可能是某個符號沒有被找到或者版本不匹配等情況。

『叄』 232.【go 語言】PProf 的使用——CPU和內存佔用分析(二)

項目更目錄下虧渣蠢執行 go tool pprof http://127.0.0.1:2022/debug/pprof/profile?seconds=30 ,結束之後會默認進入 PProf 的命梁純令行交銷陪互模式,接著輸入 top 10 ,如下圖,

項目根目錄下執行 go tool pprof http://127.0.0.1:2022/debug/pprof/heap ,結束之後會默認進入 PProf 的命令行交互模式,接著輸入 top ,如圖所示,

上面可以看到, main.main.fun1 的 cum 大小正好等於自身的 flat 大小加上 main.Add 大小的 flat 大小

『肆』 golang短連接導致cpu高

復雜的組合。golang短連接導致cpu高,使用golang進行復雜的組合運算,導致CPU佔用率非常高晌滑。CPU指中央處理器,中央處理襪謹凳器告旅作為計算機系統的運算和控制核心,是信息處理、程序運行的最終執行單元。

『伍』 golang多線程簡單邏輯

實現指定個核心最大化使用,比如核心總數減一。

必要的庫。

要使用的cpu數量,建議不全使用。

建立管道。
聲明使用的cpu數。
建立互斥關系,本例中主要為了實現所有線程執行完後再執行後續程序。

創建cpu數減1個線程

後面每個任務結束時要done一個wg,這里根據具體情況加,是循環就在每個循環里加,保證後面能全部done即可
沒有緩沖的、阻塞式的往管道傳遞字元串。
Wait是等所有線程都執行完,即增加的數字被全done掉。
關閉管道。

假設已有的函數是ReadLogs,在它的基礎上加個Wg加函數名的新函數,我覺得這種方式不改變原有的,比較舒服。
大意是:循環從管道讀取字元串,讀不到了就跳出循環。
每個ReadLogs()之後加一個wg.Done(),相當於計數減一。

ReadLogs()就是要執行的任務,不再解釋。

就是開指定個線程。
管道阻塞傳值。
wg同步。
WgReadLogs循環接收。

『陸』 cpu數量限制 golang

runtime.NumCPU()

『柒』 Go 是怎麼使用 Go 來編譯自身的

  1. Go是一個圖靈完備的語言

  2. 任何圖靈完備的語言理論上都可以用來編譯自身。比如c/c++, java, vb, php等等都可以。

至於怎麼編譯自身的:

  1. 用其它語言比如c++實現一個[Go語言編譯器-1]

  2. 用Go語言寫一個[Go語言編譯器-2]

  3. 用這個c++實現的[Go語言編譯器-1]編譯第2步裡面說的Go語言寫的[Go語言編譯器-2]

  4. 用第3步得到的[Go語言編譯器-2],再編譯一次第2步裡面說的[Go語言編譯器-2]的源碼

  5. OK,現在有一個Go語言實現的編譯器了,最開始那個c++寫的編譯器沒用了,可以扔掉不要了。以後就不停的優化使用這個Go語言實現的自身的編譯器就行了。

『捌』 go的while怎麼不耗費cpu

線程工作頻率那麼高自然會使 CPU 使用率高了,你可以換個雙核的或者四核的試試看!

閱讀全文

與go編譯不讓cpu優化參數相關的資料

熱點內容
找漫畫看應該下載什麼app 瀏覽:182
如何在vps上搭建自己的代理伺服器 瀏覽:744
nginxphp埠 瀏覽:403
內臟pdf 瀏覽:152
怎麼看雲伺服器架構 瀏覽:85
我的世界國際服為什麼登不進伺服器 瀏覽:996
微盟程序員老婆 瀏覽:930
intellij創建java 瀏覽:110
java連接odbc 瀏覽:38
啟動修復無法修復電腦命令提示符 瀏覽:359
手機編程是什麼 瀏覽:98
山東移動程序員 瀏覽:163
蘇州java程序員培訓學校 瀏覽:479
單片機液晶驅動 瀏覽:856
魔拆app里能拆到什麼 瀏覽:132
新預演算法的立法理念 瀏覽:144
wdcpphp的路徑 瀏覽:136
單片機p0口電阻 瀏覽:926
瀏覽器中調簡訊文件夾 瀏覽:595
五菱宏光空調壓縮機 瀏覽:70