1. 介绍
json-iterator
是一款快且灵活的JSON
解析器,不但100%
兼容标准库encoding/json
,而且比其更快。虽然官网说比标准包encoding/json
快6倍之多,但是随着Go
版本的不断迭代,目前平均比encoding/json
快2倍。
官网给出的性能对比结果如下:
1.1 官网性能对比图
1.2 自写程序验证
➜ go-study-example git:(main) ✗ go test -bench=. test/jsoniter_test.go -benchmem goos: darwin goarch: amd64 cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz BenchmarkUnMarshalIter-12 559245 2126 ns/op 1240 B/op 39 allocs/op BenchmarkUnMarshalJson-12 218618 5390 ns/op 1448 B/op 33 allocs/op BenchmarkMarshalIter-12 629608 1988 ns/op 1121 B/op 11 allocs/op BenchmarkMarshal-12 528918 2295 ns/op 1272 B/op 15 allocs/op PASS ok command-line-arguments 6.027s
|
经多次运行,发现反序列化(Unmarshal
)比标准包快了2.5倍,而序列化(Marshal
)基本没有什么很高的性能提升。
1.3 为什么比encoding/json
快?
jsoniter
能够比encoding/json
快的主要原因,
- 减少不必要的内存复制。
- 减少 反射(
reflect
) 的使用,对同一类型的对象,jsoniter
只反射一次之后即缓存下来。
2. 下载
go get github.com/json-iterator/go
|
3. 使用
3.1 完全兼容encoding/json
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
3.2 序列化成string
func TestMarshalToString(t *testing.T) { order := Order{ Id: 10, OrderNum: "100200300", Money: 99.99, PayTime: time.Now(), Extend: map[string]string{"name": "张三"}, } jsonStr, _ := jsoniter.MarshalToString(order) fmt.Println("jsonStr:", jsonStr) }
|
3.3 序列化成[]byte
func TestMarshalToByte(t *testing.T) { order := Order{ Id: 10, OrderNum: "100200300", Money: 99.99, PayTime: time.Now(), Extend: map[string]string{"name": "张三"}, } marshal, _ := jsoniter.Marshal(order) fmt.Println("marshal:", marshal) }
|
3.4 反序列化
func TestUnmarshalTmp(t *testing.T) { str := `{"id":10,"orderNum":"100200300","money":99.99,"payTime":"2021-12-28T23:44:36.258311+08:00","extend":{"name":"张三"}}` var order Order _ = jsoniter.UnmarshalFromString(str, &order) fmt.Println("order:", order)
var order2 Order _ = jsoniter.Unmarshal([]byte(str), &order2) fmt.Println("order2:", order2) }
|
3.5 类型不匹配场景
1. 结构体定义
type Order struct { Id int `json:"id,omitempty"` OrderNum string `json:"orderNum,omitempty"` Money float64 `json:"money,omitempty"` PayTime time.Time `json:"payTime"` Extend map[string]string `json:"extend"` }
|
2. encoding/json
func TestTypeCovert(t *testing.T) { str := `{"id":10,"orderNum":"100200300","money":"99.99","payTime":"2021-12-28T23:44:36.258311+08:00","extend":{"name":"张三"}}` var order Order err := json.Unmarshal([]byte(str), &order) if err != nil { fmt.Println("json err:", err) } fmt.Println("order: ", order) }
|
3. json-iterator
func TestTypeCovertWithJsonIter(t *testing.T) { str := `{"id":10,"orderNum":"100200300","money":"99.99","payTime":"2021-12-28T23:44:36.258311+08:00","extend":{"name":"张三"}}` var order Order var jsonNew = jsoniter.ConfigCompatibleWithStandardLibrary extra.RegisterFuzzyDecoders() err := jsonNew.Unmarshal([]byte(str), &order) if err != nil { fmt.Println("jsonNew err:", err) } fmt.Println("order: ", order) }
|
3.6 处理私有属性
type Demo struct { FirstName string `json:"firstName,omitempty"` lastName string }
func TestDealPrivate(t *testing.T) { d := Demo{ FirstName: "张", lastName: "三丰", } extra.SupportPrivateFields() var jsonNew = jsoniter.ConfigCompatibleWithStandardLibrary res, err := jsonNew.MarshalToString(d) fmt.Println("序列化-err:", err) fmt.Println("序列化-res:", res) jsonStr := `{"firstName":"张","lastName":"三丰"}` var d2 Demo err = jsonNew.UnmarshalFromString(jsonStr, &d2) fmt.Println("反序列化-err:", err) fmt.Println("反序列化-d2:", d2) }
|
3.7 时间类型处理
type timeDemo struct { CreateTime time.Time `json:"createTime"` }
func TestDealTime(t *testing.T) { td := timeDemo{CreateTime: time.Now()} var jsonNew = jsoniter.ConfigCompatibleWithStandardLibrary extra.RegisterTimeAsInt64Codec(time.Second) res, err := jsonNew.MarshalToString(td) fmt.Println("时间序列化-err:", err) fmt.Println("时间序列化-res:", res) str := `{"createTime":1640791445}` var tds timeDemo err = jsonNew.UnmarshalFromString(str, &tds) fmt.Println("时间反序列化-err:", err) fmt.Println("时间反序列化-res:", tds) }
|
3.8 直接读取Json
字符串
func TestReadJsonString(t *testing.T) { str := `{ "id":10, "extend":{ "name":"张三" }, "desc":[ { "score":"100" }, { "score":"90" } ] }` fmt.Println("id:", jsoniter.Get([]byte(str), "id").ToInt()) fmt.Println("extend.name:", jsoniter.Get([]byte(str), "extend", "name").ToString()) fmt.Println("desc.0.score:", jsoniter.Get([]byte(str), "desc", 0, "score").ToInt()) fmt.Println("desc.1.score:", jsoniter.Get([]byte(str), "desc", 1, "score").ToInt()) }
|
3.9 大驼峰转下划线
type PayInfo struct { OrderId int PayMoney float64 `json:"payMoney"` }
func TestSetNamingStrategy(t *testing.T) { payInfo := PayInfo{ OrderId: 100, PayMoney: 9.9, } extra.SetNamingStrategy(extra.LowerCaseWithUnderscores) res, _ := jsoniter.MarshalToString(payInfo) fmt.Println("序列化:", res) var p PayInfo _ = jsoniter.UnmarshalFromString(res, &p) fmt.Printf("反序列化:%+v \n", p) }
|
@设置SetNamingStrategy
后,有json
标签的使用json
标签,没有的则会自动转成xx_xx
4. 避坑:concurrent map writes
@设置extra.RegisterFuzzyDecoders()
时,注意不要在多个协程中重复设置,在init函数执行一次即可,否则会报错:fatal error: concurrent map writes
4.1 错误使用
func TestUseRegisterFuzzyDecodersWithGoroutine(t *testing.T) { payInfo := PayInfo{ OrderId: 100, PayMoney: 9.9, } for i := 0; i < 10; i++ { go func() { jsonNew := jsoniter.ConfigCompatibleWithStandardLibrary extra.RegisterFuzzyDecoders() _, _ = jsonNew.MarshalToString(payInfo) }() } time.Sleep(time.Second * 1) fmt.Println("ok") }
|
4.2 正确使用
func init() { extra.RegisterFuzzyDecoders() } func TestUseRegisterFuzzyDecodersWithGoroutine(t *testing.T) { payInfo := PayInfo{ OrderId: 100, PayMoney: 9.9, } for i := 0; i < 10; i++ { go func() { jsonNew := jsoniter.ConfigCompatibleWithStandardLibrary _, _ = jsonNew.MarshalToString(payInfo) }() } time.Sleep(time.Second * 1) fmt.Println("ok") }
|