編譯參數
理論上說 -s -w加上后,代碼段的長度會減小,理論上會提高CPU代碼cache的利用率 。(還未親自測試過)
- -X importpath.name=value 編譯期設置變量的值
- -s disable symbol table 禁用符號表
- -w disable DWARF generation 禁用調試信息
——《golang編譯參數ldflags》
使用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內聯優化》
可以關注文章中的這個內聯優化技巧:
可通過泛型golang 1.18正式發布了泛型 。-gcflags="-l"選項全局禁用內聯,與一個-l禁用內聯相反,如果傳遞兩個或兩個以上的-l則會打開內聯,并啟用更激進的內聯策略 。
泛型可以讓之前基于反射的代碼變得更加簡單,很多type assert的代碼可以去掉;基于interface的運行期動態分發,也可以轉成編譯期決定 。
由于對具體的類型產生了具體的代碼,理論上指令cache命中會提高,分支預測失敗會降低,
不過,對于有一定體量的golang團隊而言,泛型的引入要考慮的問題比較多:如何避免濫用,如何找到與之匹配的基礎庫?
在整個團隊的能力還沒準備好迎接泛型以前,使用工具生產代碼的
產生式編程或許是更容易駕馭的方法 。API使用反射編譯期決定當然是好于運行期決定的 。
我的建議是:
- 能不用就不用,可以用下面的方法代替:
- 泛型
- 代碼生成(產生式編程)
- 非得要用
- 緩存反射的到的結果
原理就是創建協程每秒一次獲取 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
經驗總結擴展閱讀
- 持續集成指南:GitLab 的 CI/CD 工具配置與使用
- 信用卡怎么查消費明細
- 消費貸款申請產生的費用高嗎
- oppo賬號的姓名怎么修改
- 租房可以換鎖芯嗎合法么 租房換鎖費用誰來承擔
- 特斯拉可以用家用電充電嗎
- 拆線多久可以用祛疤膏?
- 衛生間和廚房用什么瓷磚?
- 肉蓯蓉副作用是什么
- 計米器怎么設置參數
