go Test Benchmark 性能测试
go 性能測試
基準測試
基準測試主要是通過測試CPU和內存的效率問題,來評估被測試代碼的性能,進而找到更好的解決方案。
編寫基準測試
func BenchmarkSprintf(b *testing.B){num:=10b.ResetTimer()for i:=0;i<b.N;i++{fmt.Sprintf("%d",num)} }使用?go test?命令,加上?-bench=?標記,接受一個表達式作為參數,?.表示運行所有的基準測試
因為默認情況下?go test?會運行單元測試,為了防止單元測試的輸出影響我們查看基準測試的結果,可以使用-run=匹配一個從來沒有的單元測試方法,過濾掉單元測試的輸出,我們這里使用none,因為我們基本上不會創建這個名字的單元測試方法。
也可以使用?-run=^$, 匹配這個規則的,但是沒有,所以只會運行benchmark
go test -bench=. -run=^$有些時候在benchmark之前需要做一些準備工作,并且,我們不希望這些準備工作納入到計時里面,我們可以使用 b.ResetTimer(),代表重置計時為0,以調用時的時刻作為重新計時的開始。
看到函數后面的-8了嗎?這個表示運行時對應的GOMAXPROCS的值。
接著的20000000表示運行for循環的次數也就是調用被測試代碼的次數
最后的117 ns/op表示每次需要話費117納秒。(執行一次操作話費的時間)
以上是測試時間默認是1秒,也就是1秒的時間,調用兩千萬次,每次調用花費117納秒。
如果想讓測試運行的時間更長,可以通過-benchtime指定,比如3秒。
? hello go test -bench=. -benchtime=3s -run=none // Benchmark 名字 - CPU 循環次數 平均每次執行時間 BenchmarkSprintf-8 50000000 109 ns/op PASS // 哪個目錄下執行go test 累計耗時 ok flysnow.org/hello 5.628s可以發現,我們加長了測試時間,測試的次數變多了,但是最終的性能結果:每次執行的時間,并沒有太大變化。一般來說這個值最好不要超過3秒,意義不大。
性能對比
上面那個基準測試的例子,其實是一個int類型轉為string類型的例子,標準庫里還有幾種方法,我們看下哪種性能更加.
func BenchmarkSprintf(b *testing.B){num:=10b.ResetTimer()for i:=0;i<b.N;i++{fmt.Sprintf("%d",num)} }func BenchmarkFormat(b *testing.B){num:=int64(10)b.ResetTimer()for i:=0;i<b.N;i++{strconv.FormatInt(num,10)} }func BenchmarkItoa(b *testing.B){num:=10b.ResetTimer()for i:=0;i<b.N;i++{strconv.Itoa(num)} } ? hello go test -bench=. -run=none BenchmarkSprintf-8 20000000 117 ns/op BenchmarkFormat-8 50000000 33.3 ns/op BenchmarkItoa-8 50000000 34.9 ns/op PASS ok flysnow.org/hello 5.951s從結果上看strconv.FormatInt函數是最快的,其次是strconv.Itoa,然后是fmt.Sprintf最慢,前兩個函數性能達到了最后一個的3倍多。那么最后一個為什么這么慢的,我們再通過-benchmem找到根本原因。
? hello go test -bench=. -benchmem -run=none BenchmarkSprintf-8 20000000 110 ns/op 16 B/op 2 allocs/op BenchmarkFormat-8 50000000 31.0 ns/op 2 B/op 1 allocs/op BenchmarkItoa-8 50000000 33.1 ns/op 2 B/op 1 allocs/op PASS ok flysnow.org/hello 5.610s-benchmem可以提供每次操作分配內存的次數,以及每次操作分配的字節數。從結果我們可以看到,性能高的兩個函數,每次操作都是進行1次內存分配,而最慢的那個要分配2次;性能高的每次操作分配2個字節內存,而慢的那個函數每次需要分配16字節的內存。從這個數據我們就知道它為什么這么慢了,內存分配都占用都太高。
在代碼開發中,對于我們要求性能的地方,編寫基準測試非常重要,這有助于我們開發出性能更好的代碼。不過性能、可用性、復用性等也要有一個相對的取舍,不能為了追求性能而過度優化。
結合 pprof
pprof 性能監控
package bench import "testing" func Fib(n int) int {if n < 2 {return n}return Fib(n-1) + Fib(n-2) } func BenchmarkFib10(b *testing.B) {// run the Fib function b.N timesfor n := 0; n < b.N; n++ {Fib(10)} } go test -bench=. -benchmem -cpuprofile profile.out還可以同時看內存
go test -bench=. -benchmem -memprofile memprofile.out -cpuprofile profile.out然后就可以用輸出的文件使用pprof
go tool pprof profile.out File: bench.test Type: cpu Time: Apr 5, 2018 at 4:27pm (EDT) Duration: 2s, Total samples = 1.85s (92.40%) Entering interactive mode (type "help" for commands, "o" for options) (pprof) top Showing nodes accounting for 1.85s, 100% of 1.85s totalflat flat% sum% cum cum%1.85s 100% 100% 1.85s 100% bench.Fib0 0% 100% 1.85s 100% bench.BenchmarkFib100 0% 100% 1.85s 100% testing.(*B).launch0 0% 100% 1.85s 100% testing.(*B).runN這個是使用cpu 文件, 也可以使用內存文件
然后你也可以用list命令檢查函數需要的時間
(pprof) list Fib1.84s 2.75s (flat, cum) 148.65% of Total. . 1:package bench. . 2:. . 3:import "testing". . 4:530ms 530ms 5:func Fib(n int) int {260ms 260ms 6: if n < 2 {130ms 130ms 7: return n. . 8: }920ms 1.83s 9: return Fib(n-1) + Fib(n-2). . 10:}或者使用web命令生成圖像(png,pdf,...)
報錯:Failed to execute dot. Is Graphviz installed? Error: exec: "dot": executable file not found in %PATH%
是你電腦沒有安裝gvedit導致的
fq進入gvedit官網https://graphviz.gitlab.io/_pages/Download/Download_windows.html?下載穩定版
mac 安裝, 安裝好后就可以使用web進行展現了
brew install graphviz火焰圖
火焰圖(Flame Graph)是 Bredan Gregg 創建的一種性能分析圖表,因為它的樣子近似火焰而得名。
火焰圖 svg 文件可以通過瀏覽器打開,它對于調用圖的最優點是它是動態的:可以通過點擊每個方塊來 zoom in 分析它上面的內容。
火焰圖的調用順序從下到上,每個方塊代表一個函數,它上面一層表示這個函數會調用哪些函數,方塊的大小代表了占用 CPU 使用的長短。火焰圖的配色并沒有特殊的意義,默認的紅、黃配色是為了更像火焰而已。
runtime/pprof分析項目, 會在當前文件夾內導出profile文件。然后用火焰圖去分析,就不能指定域名了,要指定文件。
go-torch
網上介紹大部分使用uber的開源工具
go-torch。這是 uber 開源的一個工具,可以直接讀取 golang profiling 數據,并生成一個火焰圖的 svg 文件。
go-torch 工具的使用非常簡單,沒有任何參數的話,它會嘗試從?http://localhost:8080/debug/pprof/profile?獲取 profiling 數據。它有三個常用的參數可以調整:
- -u --url:要訪問的 URL,這里只是主機和端口部分
- -s --suffix:pprof profile 的路徑,默認為 /debug/pprof/profile
- --seconds:要執行 profiling 的時間長度,默認為 30s
原生支持
從 Go 1.11 開始, 火焰圖被集成進入 Go 官方的 pprof 庫.
# This will listen on :8081 and open a browser. # Change :8081 to a port of your choice. $ go tool pprof -http=":8081" [binary] [profile]如果低于1.11版本那么請從git pprof
# Get the pprof tool directly $ go get -u github.com/google/pprof$ pprof -http=":8081" [binary] [profile]pprof README.md
一個web 小例子
package mainimport ("fmt""log""net/http"_ "net/http/pprof""time" )func sayHelloHandler(w http.ResponseWriter, r *http.Request) {hellowold(10000)fmt.Println("path", r.URL.Path)fmt.Println("scheme", r.URL.Scheme)fmt.Fprintf(w, "Hello world!\n") //這個寫入到w的是輸出到客戶端的 }func main() {http.HandleFunc("/", sayHelloHandler) // 設置訪問路由log.Fatal(http.ListenAndServe(":8080", nil)) }func hellowold(times int) {time.Sleep(time.Second)var counter intfor i := 0; i < times; i++ {for j := 0; j < times; j++ {counter++}} }使用下面的命令開啟監控,然后訪問幾次localhost:8080
go tool pprof -http=":8081" http://localhost:8080/debug/pprof/profile過一會兒會產生個web窗口, 選擇 VIEW->Flame Graph 得到火焰圖形
http://localhost:8081/ui/flamegraphTesting flags
go 測試后面可以跟哪些參數
Testing flags
常用flag
- -bench regexp:性能測試,支持表達式對測試函數進行篩選。-bench .則是對所有的benchmark函數測試
- -benchmem:性能測試的時候顯示測試函數的內存分配的統計信息
- -count n:運行測試和性能多少此,默認一次
- -run regexp:只運行特定的測試函數, 比如-run ABC只測試函數名中包含ABC的測試函數
- -timeout t:測試時間如果超過t, panic,默認10分鐘
- -v:顯示測試的詳細信息,也會把Log、Logf方法的日志顯示出來
Go 1.7中開始支持?sub-test的概念。
測試注意和調優
golang性能測試與調優
- 避免頻繁調用timer
- 避免測試數據過大
參考
Go語言實戰筆記(二十一)| Go 單元測試
Go語言實戰筆記(二十二)| Go 基準測試
Profile your golang benchmark with pprof
深入Go語言 - 12
Go單元測試&性能測試
golang性能測試與調優
go pprof 性能分析
go tool pprof
Go 性能測試工具PProf--火焰圖
PS: 覺得不錯的請點個贊吧!! (? ??_??)?
總結
以上是生活随笔為你收集整理的go Test Benchmark 性能测试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python 自动化教程(3) : 自动
- 下一篇: xcode左侧不显示工程文件目录,提示N