Go 一行代碼測量函數的執行時間
Golang Tips 是翻譯的 Phuong Le @func25[1] 陸陸續續的發表的推文,目前已經發表 70 + 了。我徵得 Phuong Le 的同意後,會逐步把這些推翻翻譯過來,發佈到公衆號上。
因爲是推文,可能原作者的內容比較簡單,比如第一個 tip 就一張圖片,我會相應的進行擴充,豐富其內容。 後續也會在 github 建立一個項目,大家都可以參與進行翻譯。
我們可以通過 defer
,實現一行代碼來測量某個函數的執行時間:
func main() {
defer TrackTime(time.Now()) // 一行代碼
time.Sleep(time.Second)
}
func TrackTime(start time.Time) time.Duration {
elapsed := time.Since(start)
fmt.Println("elapsed:", elapsed)
return elapsed
}
// elapsed: 1.000704416s
這個 defer
的函數 TraceTime
放在函數內需要測量的起始點,它的參數 (start
) 在此時就會計算出來,在函數返回的時候,它的函數體就會被調用,這是 end
時間也知道了,這樣就可以巧妙的計算出來函數執行的時間了。
以下是補充材料
我們還可以使用下面的寫法,但是更好更通用些:
func TrackTime(name string) func() {
start := time.Now()
return func() {
fmt.Printf("%s took %v\n", name, time.Since(start))
}
}
func main() {
defer TrackTime("main")() // 也是一行代碼
time.Sleep(time.Second * 2)
}
這個 defer
的 TraceTime
傳入一個輔助信息字符串,方便打日誌的能和其它的測量函數所區分。TraceTime
返回一個類型爲 func()
函數匿名函數,這纔是 defer
真正調用的函數,它會打印出要測量的函數真正花費的時間。
相比較上面的測量方法,這個函數可以傳入輔助字符串,並且不需要自己再調用 time.Now()
獲得開始時間。
另外,我還想補充一個測試性能的時候的輔助庫:hrtime[2])。 一般我們會寫 Benchmark 的測試代碼來測試一段代碼邏輯 (一般是一個函數,但是也可以是多個函數和語句組成的一段代碼邏輯) 的性能,但是有的時候,我們可能想寫一個程序,更靈活的進行測試,甚至希望得到時間花費的分佈情況, hrtime 就是幹這個的,就像它的簡介中所說,它是 Go 語言中的高精度計時與基準測試庫。
首先我們看一下它的使用方法:
package main
import (
"fmt"
"time"
"github.com/loov/hrtime"
)
func main() {
start := hrtime.Now()
time.Sleep(1000 * time.Nanosecond)
fmt.Println(hrtime.Since(start))
const numberOfExperiments = 4096
bench := hrtime.NewBenchmark(numberOfExperiments)
for bench.Next() {
time.Sleep(1000 * time.Nanosecond)
}
fmt.Println(bench.Histogram(10))
}
單純的測量一段代碼的執行時間,和常規的我們使用 time package 方法一樣,你也可以採用前面介紹的方法,實現一行代碼的封裝。
同時,類似標準庫的 Benchmark 的測量性能的方法,你也可以利用 bench := hrtime.NewBenchmark(numberOfExperiments)
生成一個 bench
,進行性能測試,最後通過 bench.Histogram(10)
生成直方圖。比如這個例子,我們測試 Sleep 1 微秒時,實際程序會休眠多少微秒。
在我的 Mac mini 的機器上測試,可以看到真正休眠在 5 微秒左右,絕大部分時間落在了 15 微秒以內。
參考資料
[1]
@func25: https://twitter.com/func25
[2]
hrtime: https://github.com/loov/hrtime
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/LJoIHHDB5SflvtOhGZCtLw