Go 程式的效能最佳化及 pprof 的使用

來源:互聯網
上載者:User

程式的效能最佳化無非就是對程式佔用資源的最佳化。對於伺服器而言,最重要的兩項資源莫過於 CPU 和記憶體。效能最佳化,就是在對於不影響程式資料處理能力的情況下,我們通常要求程式的 CPU 的記憶體佔用盡量低。反過來說,也就是當程式 CPU 和記憶體佔用不變的情況下,盡量地提高程式的資料處理能力或者說是輸送量。

Go 的原生工具鏈中提供了非常多豐富的工具供開發人員使用,其中包括 pprof

對於 pprof 的使用要分成下面兩部分來說。

Web 程式使用 pprof

先寫一個簡單的 Web 服務程式。程式在 9876 連接埠上接收請求。

package mainimport (    "bytes"    "io/ioutil"    "log"    "math/rand"    "net/http"    _ "net/http/pprof")func main() {    http.HandleFunc("/test", handler)    log.Fatal(http.ListenAndServe(":9876", nil))}func handler(w http.ResponseWriter, r *http.Request) {    err := r.ParseForm()    if nil != err {        w.Write([]byte(err.Error()))        return    }    doSomeThingOne(10000)    buff := genSomeBytes()    b, err := ioutil.ReadAll(buff)    if nil != err {        w.Write([]byte(err.Error()))        return    }    w.Write(b)}func doSomeThingOne(times int) {    for i := 0; i < times; i++ {        for j := 0; j < times; j++ {        }    }}func genSomeBytes() *bytes.Buffer {    var buff bytes.Buffer    for i := 1; i < 20000; i++ {        buff.Write([]byte{'0' + byte(rand.Intn(10))})    }    return &buff}

可以看到我們只是簡單地引入了 net/http/pprof ,並未顯示地使用。

啟動程式。

我們用 wrk 來簡單地類比請求。

wrk -c 400 -t 8 -d 3m http://localhost:9876/test

這時我們開啟 http://localhost:9876/debug/pprof,會顯示如下頁面:

img

使用者可以點擊相應的連結瀏覽內容。不過這不是我們重點講述的,而且這些內容看起來並不直觀。

我們開啟連結 http://localhost:9876/debug/pprof/profile 稍後片刻,可以下載到檔案 profile

使用 Go 內建的 pprof 工具開啟。go tool pprof test profile。(proof 後跟的 test 為程式編譯的可執行檔)

輸入 top 命令得到:

img

可以看到 cpu 佔用前 10 的函數,我們可以對此分析進行最佳化。

只是這樣可能還不是很直觀。

我們輸入命令 web(需要事先安裝 graphviz,macOS 下可以 brew install graphviz),會在瀏覽器中開啟介面如下:

img

可以看到 main.doSomeThingOne 佔用了 92.46% 的 CPU 時間,需要對其進行最佳化。

Web 形式的 CPU 時間圖對於最佳化已經完全夠用,這邊再介紹一下火焰圖的產生。macOS 推薦使用 go-torch 工具。使用方法和 go tool pprof 相似。

go-torch test profile 會產生 torch.svg 檔案。可以用瀏覽器開啟,。

img

剛才只是講了 CPU 的佔用分析檔案的產生查看,其實記憶體快照的產生相似。http://localhost:9876/debug/pprof/heap,會下載得到 heap.gz 檔案。

我們同樣可以使用 go tool pprof test heap.gz,然後輸入 topweb 命令查看相關內容。

imgimg

通用程式使用 pprof

我們寫的 Go 程式並非都是 Web 程式,這時候再使用上面的方法就不行了。

我們仍然可以使用 pprof 工具,但引入的位置為 runtime/pprof

這裡貼出兩個函數,作為樣本:

// 產生 CPU 報告func cpuProfile() {    f, err := os.OpenFile("cpu.prof", os.O_RDWR|os.O_CREATE, 0644)    if err != nil {        log.Fatal(err)    }    defer f.Close()    log.Println("CPU Profile started")    pprof.StartCPUProfile(f)    defer pprof.StopCPUProfile()    time.Sleep(60 * time.Second)    fmt.Println("CPU Profile stopped")}// 產生堆記憶體報告func heapProfile() {    f, err := os.OpenFile("heap.prof", os.O_RDWR|os.O_CREATE, 0644)    if err != nil {        log.Fatal(err)    }    defer f.Close()    time.Sleep(30 * time.Second)    pprof.WriteHeapProfile(f)    fmt.Println("Heap Profile generated")}

兩個函數分別會產生 cpu.profheap.prof 檔案。仍然可以使用 go tool pprof 工具進行分析,在此就不贅述。

Trace 報告

直接貼代碼:

// 產生追蹤報告func traceProfile() {    f, err := os.OpenFile("trace.out", os.O_RDWR|os.O_CREATE, 0644)    if err != nil {        log.Fatal(err)    }    defer f.Close()    log.Println("Trace started")    trace.Start(f)    defer trace.Stop()    time.Sleep(60 * time.Second)    fmt.Println("Trace stopped")}

使用工具 go tool trace 進行分析,會得到非常詳細的追蹤報告,供更深入的程式分析最佳化。由於報告內容比較複雜,且使用方法類似,就不繼續了。讀者可自行嘗試。

貼張網上的圖給大家大概看一下:

img

每個golang包只需要一篇最好的文章 系列
http://www.nextblockchain.top/books/golangpackage/summary

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.