Golang ---json解析

golang官方爲咱們提供了標準的json解析庫–encoding/json,大部分狀況下,使用它已經夠用了。不過這個解析包有個很大的問題–性能。它不夠快,若是咱們開發高性能、高併發的網絡服務就沒法知足,這時就須要高性能的json解析庫,目前性能比較高的有json-iteratoreasyjsongit

如今咱們須要引進一個高性能的json解析庫,這裏以json-iterator爲例,可是咱們所有換掉又不放心,因此能夠先小範圍的測試下,這時候咱們就須要兩個解析庫並存,那麼這時候咱們如何選擇咱們須要的解析庫編譯和運行呢?github

解決上面問題的辦法就是條件編譯。Go語言爲咱們提供了基於tags的編譯約束來解決這個問題。golang

統一JSON庫

咱們先舉個例子看看結果。如今咱們須要兩個庫並存,因此咱們先得統一這兩個庫的用法(參考適配器模式),這裏咱們使用一個自定義的json包來適配encoding/jsonjson-iteratorjson

json/json.gobash

// +build !jsoniter

package json

import (
	"encoding/json"
	"fmt"
)

func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
	fmt.Println("Use [encoding/json] package")
	return json.MarshalIndent(v,prefix,indent)
}

  

json/jsoniter.go網絡

// +build jsoniter

package json

import (
	"fmt"
	"github.com/json-iterator/go"
)

var (
	json = jsoniter.ConfigCompatibleWithStandardLibrary
)

func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
	fmt.Println("Use [jsoniter] package")
	return json.MarshalIndent(v,prefix,indent)
}

  

目錄結構以下:併發

json
├── json.go
└── jsoniter.go

例子中以MarshalIndent函數爲例,咱們發現json包下的兩個go文件中都有MarshalIndent函數的定義,而且簽名一致,可是它們又是使用不一樣的json解析庫實現,這就是咱們統一適配包裝後的結果,調用統一了。函數

Demo演示

爲了區分調用的是哪一個json庫的具體實現,打印日誌,以便區分。如今咱們使用json.MarshalIndent測試一下。高併發

package main

import (
	"fmt"
	"json"
)

func main() {
	u := user{"Mike", 30}
	b, err := json.MarshalIndent(u, "", "  ")

	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(string(b))
	}

}

type user struct {
	Name string
	Age  int
}

 使用很簡單,把一個user結構體對象轉爲json字符串,並打印出來。咱們運行go run main.go看看結果。性能

Use [encoding/json] package

{

"Name": "Mike",

"Age": 30

}

 保持咱們默認使用encoding/json庫的方式不變。如今咱們換一種編譯運行方式:

go run -tags=jsoniter main.go

  此次運行和上次不一樣的地方在於咱們加了-tags=jsoniter,而後就使用了json-iterator這個json庫,這就是選擇性的條件編譯,達到了咱們小部分測試新的json庫的目的。

 

條件編譯

咱們發現,條件編譯的關鍵在於-tags=jsoniter,也就是-tags這個標誌,這就是Go語言爲咱們提供的條件編譯的方式之一。

好了,回過頭來看咱們剛開始時json/json.gojson/jsoniter.go這兩個Go文件的頂部,都有一行註釋:

// +build !jsoniter // +build jsoniter 

這兩行是Go語言條件編譯的關鍵。+build能夠理解爲條件編譯tags的聲明關鍵字,後面跟着tags的條件。

// +build !jsoniter表示,tags不是jsoniter的時候編譯這個Go文件。 // +build jsoniter表示,tags是jsoniter的時候編譯這個Go文件。

也就是說,這兩種條件是互斥的,只有當tags=jsoniter的時候,纔會使用json-iterator,其餘狀況使用encoding/json

小結

利用條件編譯,咱們實現了靈活選擇json解析庫的目的,且tags只是其中的一部分,Go語言還能夠根據Go文件後綴進行條件編譯。

相關文章
相關標籤/搜索