Golang 語言中怎麼提升 JSON 編解碼的性能?

大家好,我是 frank。
歡迎大家點擊上方藍色文字「Golang 語言開發棧」關注公衆號。
設爲星標,第一時間接收推送文章。
文末掃碼,大家一起學 Golang 語言。

01

介紹

在 Golang 語言中,我們一般會使用標準庫 encoding/json 序列化 / 反序列化 JSON,但是因爲 encoding/json 需要使用反射,所以如果在性能要求比較高的場景中,它就不太合適了。

本文我們要介紹的三方庫 easyjson,它提供了快速且簡單的方式去序列化和反序列化 Golang 結構體 / JSON,官方文檔介紹,在性能測試中,easyjson 比標準庫 encoding/json 高 4~5 倍。

easyjson 的目標是保持生成的 Golang 代碼足夠簡單,以便它可以很容易地優化或修復,並且通過提供標準庫 encoding/json 中無法提供的選項,爲用戶提供自定義生成代碼的能力,例如生成 snake_case 名稱或默認啓用 omitempty 行爲。

02

安裝和生成代碼

在準備使用 easyjson 之前,我們需要先安裝 easyjson

安裝命令:

go get -u github.com/mailru/easyjson/...

安裝成功之後,我們就可以使用 easyjson 生成代碼了,也非常簡單,僅需運行以下命令。

生成代碼命令:

easyjson -all <file>.go

運行上面這條命令,會自動生成一個文件 <file>_easyjson.go,文件中包含 <file>.go 文件中所有結構體對應的 marshaler 和 unmarshaler 方法。

需要注意的是,我們使用 easyjson 命令生成代碼之前,需要設置 GOPATH 環境變量。

如果我們使用 easyjson 命令生成代碼時,沒有指定 -all 選項,我們需要在需要生成相應代碼的結構體上方添加一個標籤 //easyjson:json

我們使用 easyjson -all <file>.go 生成代碼時,如果文件中個別結構體不需要生成相應代碼,我們可以在該結構體上方添加一個標籤 //easyjson:skip

除了 -all 選項,還有一些其他比較常用的選項,限於篇幅,我們不再贅述,感興趣的讀者朋友們可以查閱官方文檔瞭解更多。

03

使用示例

讀者朋友們閱讀完以上內容後,想必一定會動手操練一把,以下是本文的示例代碼,供讀者朋友們做個參考,完整代碼可以翻閱 GitHub。

結構體:

type User struct {
 ID uint64 `json:"id"`
 Name string `json:"name"`
}

序列化:

// 序列化
func encode() {
 user := &model.User{
  ID:   1,
  Name: "lucy",
 }
 bs, err := user.MarshalJSON()
 if err != nil {
  fmt.Println(err)
  return
 }
 fmt.Printf("encode() type=%T\nbs=%v\nstr=%s\n", bs, bs, string(bs))
}

反序列化:

// 反序列化
func decode() {
 user := new(model.User)
 str := `{"id":1,"name":"lucy"}`
 err := user.UnmarshalJSON([]byte(str))
 if err != nil {
  fmt.Println(err)
  return
 }
 fmt.Printf("decode() user=%+v\n", user)
}

04

總結

本文我們重點介紹了相比 Golang 標準庫 encoding/json 性能較高的三方庫 easyjson,包括安裝、使用和示例代碼。感興趣的讀者朋友,可以 benchmark 做個對比。

讀到這裏,讀者朋友們可能會有個疑問,既然 easyjson 不會使用反射,爲什麼結構體定義時還使用 json 標籤,實際上,easyjson 在生成代碼時,也使用了反射。

在應用程序開發中,如果標準庫可以滿足需求,不建議引入三方庫,導致增加應用程序的維護成本。

參考資料:

https://github.com/mailru/easyjson

https://pkg.go.dev/encoding/json@go1.16.7

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/wkqk1cgYKWnbIsHqoTA5UA