国产精品免费嫩草研究院|无遮羞动漫在线观看AV|国产麻豆精品传媒AV国产在线|村在线观看|寂寞情人1正版|韩国床震韩国床震古|精品系列专区久久

用golang開發系統軟件的一些細節( 六 )


編譯參數

  • -X importpath.name=value 編譯期設置變量的值
  • -s disable symbol table 禁用符號表
  • -w disable DWARF generation 禁用調試信息
    ——《golang編譯參數ldflags》
理論上說 -s -w加上后,代碼段的長度會減小,理論上會提高CPU代碼cache的利用率 。(還未親自測試過)
使用runtime中的非導出函數runtime中有的底層函數是匯編實現的,性能很高,但是不是export類型 。
這時候可以用鏈接聲明來使用這些函數:
//go:noescape//go:linkname memmove runtime.memmove//goland:noinspection GoUnusedParameterfunc memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)func memmove(to, from unsafe.Pointer, n uintptr)// 通過上面的聲明后,就可以在代碼中使用底層的memmove函數了 。這個函數相當于c中的memcpy()具體的細節請看這篇文章:《Go的2個黑魔法技巧》(騰訊 pedrogao)
函數內聯golang的小函數默認就是內聯的 。
可以通過函數前的注釋 //go:noinline來取消內聯,不過似乎沒有理由這么做 。
關于函數內聯的深層知識還是值得學習的,推薦這篇文章:《詳解Go內聯優化》
可以關注文章中的這個內聯優化技巧:
可通過-gcflags="-l"選項全局禁用內聯,與一個-l禁用內聯相反,如果傳遞兩個或兩個以上的-l則會打開內聯,并啟用更激進的內聯策略 。
泛型golang 1.18正式發布了泛型 。
泛型可以讓之前基于反射的代碼變得更加簡單,很多type assert的代碼可以去掉;基于interface的運行期動態分發,也可以轉成編譯期決定 。
由于對具體的類型產生了具體的代碼,理論上指令cache命中會提高,分支預測失敗會降低,
不過,對于有一定體量的golang團隊而言,泛型的引入要考慮的問題比較多:如何避免濫用,如何找到與之匹配的基礎庫?
在整個團隊的能力還沒準備好迎接泛型以前,使用工具生產代碼的產生式編程或許是更容易駕馭的方法 。
API使用反射編譯期決定當然是好于運行期決定的 。
我的建議是:
  • 能不用就不用,可以用下面的方法代替:
    • 泛型
    • 代碼生成(產生式編程)
  • 非得要用
    • 緩存反射的到的結果
有的場景下,標準庫提供的API不夠好 。下面列舉一些自己認識的fast-xx組件 。fasttime組件,低精度的time.Now()源碼請見:https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/lib/fasttime/fasttime.go
原理就是創建協程每秒一次獲取 time.Now(),然后一秒以內取時間戳就只是訪問全局變量 。
我測試過:性能比直接使用time.Now()快三倍左右 。
fastrand,繞開rand庫的鎖源碼請見:https://github.com/valyala/fastrand
超長字符串輸出的優化:quicktemplate假設一次要輸出幾兆字節的JSON字符串,如何優化性能?
VictoriaMetrics中的vm-select就遇到了這個問題,當一個大查詢需要返回很多的metrics數據的時候,其輸出的json的體積非常可觀 。
如果把數據先放到一個大數組,再使用json.Marsharl,則一方面要頻繁申請釋放內存,另一方面會帶來內存使用量的劇烈抖動 。vm-select的解決方式是使用quicktemplate庫——把json看成是字符串流的輸出 。
具體代碼請看:https://github.com/valyala/quicktemplate

經驗總結擴展閱讀