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

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


sync.Pool不如上面的方法節省內存,但好處是可以縮容 。
數量可控的中型對象有的時候,我們可能需要一些定額數量的對象,并且對這些對象復用 。
這時可以使用channel來做內存池 。需要時從channel取出,用完放回channel 。
slice的復用fasthttp, VictoriaMetrics等組件的作者 valyala可謂是把slice復用這個技巧玩上了天,具體可以看fasthttp主頁上的Tricks with []byte buffers這部分介紹 。
概要的總結起來就是:[]byte這樣的數組分配后,不要釋放,然后下次使用前,用slice=slice[:0]來清空,繼續使用其上次分配好的cap指向的空間 。
這篇中文的總結也非常不錯:《fasthttp對性能的優化壓榨》
valyala大神還寫了個 bytebufferpool,對[]byte重用的場景進行了封裝 。
避免容器空間動態增長對于slice和map而言,在預先可以預估其空間占用的情況下,通過指定大小來減少容器操作期間引起的空間動態增長 。特別是map,不但要拷貝數據,還要做rehash操作 。
func xxx(){  slice := make([]byte, 0, 1024)  // 有的時候,golangci-lint會提示未指定空間的情況  m := make(map[int64]struct{}, 1000)}大神技巧:用slice代替map此技巧源于valyala大神 。
假設有一個很小的map需要插入和查詢,那么把所有key-value順序追加到一個slice中,然后遍歷查找——其性能損耗可能比分配map帶來的GC消耗還要小 。

  1. map變成slice,少了很多動態調整的空間
  2. 如果整個slice能夠塞進CPU cache line,則其遍歷可能比從內存load更加快速
具體請見這篇:《golang第三方庫fasthttp為什么要使用slice而不是map來存儲header?》
避免棧逃逸golang中非常酷的一個語法特點就是沒有堆和棧的區別 。編譯器會自動識別哪些對象該放在堆上,哪些對象該放在棧上 。
func xxx() *ABigStruct{  a := new(ABigStruct)  // 看起來是在堆上的對象  var b ABigStruct      // 看起來是棧上的對象  // do something  // not return a   // a雖然是對象指針,但僅限于函數內使用,所以編譯器可能把a放在棧上  return &b   // b超出了函數的作用域,編譯器會把b放在堆上 。}valyala大神的經驗:先找出程序的hot path,然后在hot path上做棧逃逸的分析 。盡量避免hot path上的堆內存分配,就能減輕GC壓力,提升性能 。
fasthttp首頁上的介紹:
Fast HTTP package for Go. Tuned for high performance. Zero memory allocations in hot paths. Up to 10x faster than net/http
這篇文章介紹了偵測棧逃逸的方法:
驗證某個函數的變量是否發生逃逸的方法有兩個:
  • go run -gcflags "-m -l" (-m打印逃逸分析信息,-l禁止內聯編譯);例:
?  testProj go run -gcflags "-m -l" internal/test1/main.go# command-line-argumentsinternal/test1/main.go:4:2: moved to heap: ainternal/test1/main.go:5:11: main make([]*int, 1) does not escape
  • go tool compile -S main.go | grep runtime.newobject(匯編代碼中搜runtime.newobject指令,該指令用于生成堆對象),例:
?  testProj go tool compile -S internal/test1/main.go | grep newobject        0x0028 00040 (internal/test1/main.go:4) CALL    runtime.newobject(SB)

經驗總結擴展閱讀