我注意到,當我在 Go HTTP 服務器的上下文中計時 JSON 解組時,即使對于小對象也需要 30,000+ 納秒。這對我來說似乎很大,所以我運行了一些獨立的基準測試,結果令人驚訝地顯示每次解組的平均時間約為 500 納米。為了更深入地研究這個問題,我編寫了一個程序,它只對同一個小對象執行一系列解組,這表明第一個解組很慢,而后續的要快得多:package mainimport ( "time" "fmt" "encoding/json")var b []bytetype Dog struct { Age int `json:"Age"`}func unmarshalDog() { dogCopy := Dog{} start := time.Now().UnixNano() json.Unmarshal(b, &dogCopy) end := time.Now().UnixNano() fmt.Printf("Time to marshal/unmarshal: %d\n", end-start)}func main() { // Marshal an object into a byte array which we will repeatedly unmarshal from d := Dog { Age: 5, } var err error b, err = json.Marshal(d) if err != nil { panic(err) } for i := 0; i < 20; i++ { unmarshalDog() } // Allow the goroutines to finish before terminating execution. time.Sleep(3 * time.Second)}輸出:$ go run testJSONPerformance.goTime to marshal/unmarshal: 34127Time to marshal/unmarshal: 1465Time to marshal/unmarshal: 979Time to marshal/unmarshal: 892Time to marshal/unmarshal: 849Time to marshal/unmarshal: 814Time to marshal/unmarshal: 822Time to marshal/unmarshal: 822Time to marshal/unmarshal: 815Time to marshal/unmarshal: 829Time to marshal/unmarshal: 822Time to marshal/unmarshal: 819unmarshalDog()更有趣的是,當我運行同一個程序但在一個單獨的 goroutine 中運行每次調用viago unmarshalDog()時,預熱現象消失并且平均解組時間長得多:Time to marshal/unmarshal: 36540Time to marshal/unmarshal: 4652Time to marshal/unmarshal: 56959Time to marshal/unmarshal: 3887Time to marshal/unmarshal: 57068Time to marshal/unmarshal: 3519Time to marshal/unmarshal: 37160我還嘗試了一個版本,而不是解組相同的字節數組,我每次都編組和解組一個不同的對象(以防某種運行時緩存正在進行)。在這種情況下,結果是一樣的。我非常想知道這種明顯的“熱身”是怎么回事。在 HTTP 服務器的上下文中,每個請求都會得到一個不同的 goroutine,因此每個解組平均來說都非常慢。這似乎不是最理想的,因為顯然 Go 有可能在特定上下文中用 1/50 的時間進行解組。所有直覺贊賞!
為什么在“預熱”之后解組 JSON 的速度要快得多?
慕的地6264312
2023-03-21 17:33:18