寫項(xiàng)目一直需要進(jìn)行序列化,聽到了,也看到了很多同學(xué)老師對(duì)各個(gè)golang的json
庫(kù)進(jìn)行測(cè)評(píng)。那本人為什么還要繼續(xù)進(jìn)行這一次測(cè)評(píng)呢?
因?yàn)閷?shí)踐過(guò)的知識(shí)最有說(shuō)服力,也是屬于自己的,我也希望看到本博文的同學(xué)老師可以修改和執(zhí)行測(cè)評(píng)的代碼執(zhí)行一遍,我相信會(huì)有不一定的體會(huì)。
本次測(cè)評(píng)我選擇了類庫(kù)有:
序號(hào) | 類庫(kù) | 地址 | 備注 | |
---|---|---|---|---|
1 | encoding/json | Golan | ||
2 | easyjson | github.com/mailru/easyjson | ||
3 | ffjson | github.com/mailru/easyjson | ||
4 | iterator/json | github.com/json-iterator/go |
主要是針對(duì)上述的類型進(jìn)行,本人采用了對(duì)不同的類庫(kù)使用不同的結(jié)構(gòu)體(僅僅是結(jié)構(gòu)體名稱不同,字段順序和類型一樣)。
環(huán)境為MacBook Pro(Core i5處理器/8GB內(nèi)存)go1.8.3 darwin/amd64
bench代碼如下:
package jsonbench
import (
"encoding/gob"
"encoding/json"
"github.com/json-iterator/go"
"github.com/mailru/easyjson"
"github.com/pquerna/ffjson/ffjson"
"testing"
)
var (
iterator = jsoniter.ConfigCompatibleWithStandardLibrary
// easyjson
as = AgentService{
ServiceName: "kaleidoscope_api",
Version: "1517558949087295000_1298498081",
ServiceId: "kaleidoscope_kaleidoscope.dev.igetget.com_v1.2",
Address: "kaleidoscope.dev.igetget.com",
Port: 80,
Metadata: map[string]string{},
ConnectTimeOut: 1000,
ConnectType: "LONG",
ReadTimeOut: 1000,
WriteTimeOut: 1000,
Protocol: "HTTP",
Balance: "Random",
Idcs: "hu,hd,hn",
Converter: "json",
Retry: 3,
}
service = as.ToService()
asBytes, _ = json.Marshal(as)
serviceBytes, _ = json.Marshal(service)
asStr = string(asBytes)
serviceStr = string(serviceBytes)
asGonBytes, _ = GobEncode(as)
serviceGonBytes, _ = GobEncode(service)
// std
asstd = AgentServiceSTD{
ServiceName: "kaleidoscope_api",
Version: "1517558949087295000_1298498081",
ServiceId: "kaleidoscope_kaleidoscope.dev.igetget.com_v1.2",
Address: "kaleidoscope.dev.igetget.com",
Port: 80,
Metadata: map[string]string{},
ConnectTimeOut: 1000,
ConnectType: "LONG",
ReadTimeOut: 1000,
WriteTimeOut: 1000,
Protocol: "HTTP",
Balance: "Random",
Idcs: "hu,hd,hn",
Converter: "json",
Retry: 3,
}
servicestd = asstd.ToServiceSTD()
asBytesstd, _ = json.Marshal(asstd)
serviceBytesstd, _ = json.Marshal(servicestd)
asStrstd = string(asBytesstd)
serviceStrstd = string(serviceBytesstd)
asGonBytesstd, _ = GobEncode(asstd)
serviceGonBytesstd, _ = GobEncode(servicestd)
)
// go test -bench=".*"
func init() {
gob.Register(AgentService{})
}
func Benchmark_STD_Marshal1(b *testing.B) {
for i := 0; i < b.N*10; i++ {
_, err := json.Marshal(asstd)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_STD_Marshal2(b *testing.B) {
for i := 0; i < b.N*10; i++ {
_, err := json.Marshal(servicestd)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_EASYJSON_STD_Marshal1(b *testing.B) {
for i := 0; i < b.N*10; i++ {
_, err := json.Marshal(as)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_EASYJSON_STD_Marshal2(b *testing.B) {
for i := 0; i < b.N*10; i++ {
_, err := json.Marshal(service)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_EASYJSON_Marshal1(b *testing.B) {
for i := 0; i < b.N*10; i++ {
_, err := easyjson.Marshal(as)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_EASYJSON_Marshal2(b *testing.B) {
for i := 0; i < b.N*10; i++ {
_, err := easyjson.Marshal(service)
if err != nil {
b.Error(err)
}
}
}
//
func Benchmark_ITERATOR_Marshal1(b *testing.B) {
for i := 0; i < b.N*10; i++ {
_, err := iterator.Marshal(asstd)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_ITERATOR_Marshal2(b *testing.B) {
for i := 0; i < b.N*10; i++ {
_, err := iterator.Marshal(servicestd)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_FFJSON_Marshal1(b *testing.B) {
for i := 0; i < b.N*10; i++ {
_, err := ffjson.Marshal(asstd)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_FFJSON_Marshal2(b *testing.B) {
for i := 0; i < b.N*10; i++ {
_, err := ffjson.Marshal(servicestd)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_GOB_Encode1(b *testing.B) {
for i := 0; i < b.N*10; i++ {
as.Port = i
GobEncode(as)
}
}
func Benchmark_GOB_Encode2(b *testing.B) {
for i := 0; i < b.N*10; i++ {
GobEncode(service)
}
}
func Benchmark_STD_Unmarshal1(b *testing.B) {
tmp := AgentServiceSTD{}
for i := 0; i < b.N*10; i++ {
as.Port = i
err := json.Unmarshal(asBytesstd, &tmp)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_STD_Unmarshal2(b *testing.B) {
tmp := ServiceSTD{}
for i := 0; i < b.N*10; i++ {
as.Port = i
err := json.Unmarshal(serviceBytesstd, &tmp)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_EASYJSON_STD_Unmarshal1(b *testing.B) {
tmp := AgentService{}
for i := 0; i < b.N*10; i++ {
as.Port = i
err := json.Unmarshal(asBytes, &tmp)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_EASYJSON_STD_Unmarshal2(b *testing.B) {
tmp := Service{}
for i := 0; i < b.N*10; i++ {
as.Port = i
err := json.Unmarshal(serviceBytes, &tmp)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_EASYJSON_Unmarshal1(b *testing.B) {
tmp := AgentService{}
for i := 0; i < b.N*10; i++ {
as.Port = i
err := easyjson.Unmarshal(asBytes, &tmp)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_EASYJSON_Unmarshal2(b *testing.B) {
tmp := Service{}
for i := 0; i < b.N*10; i++ {
as.Port = i
err := easyjson.Unmarshal(serviceBytes, &tmp)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_ITERATOR_UnMarshal1(b *testing.B) {
tmp := ServiceSTD{}
for i := 0; i < b.N*10; i++ {
as.Port = i
err := iterator.Unmarshal(serviceBytesstd, &tmp)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_ITERATOR_UnMarshal2(b *testing.B) {
tmp := ServiceSTD{}
for i := 0; i < b.N*10; i++ {
as.Port = i
err := iterator.Unmarshal(serviceBytesstd, &tmp)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_FFJSON_UnMarshal1(b *testing.B) {
tmp := ServiceSTD{}
for i := 0; i < b.N*10; i++ {
as.Port = i
err := ffjson.Unmarshal(serviceBytesstd, &tmp)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_FFJSON_UnMarshal2(b *testing.B) {
tmp := ServiceSTD{}
for i := 0; i < b.N*10; i++ {
as.Port = i
err := ffjson.Unmarshal(serviceBytesstd, &tmp)
if err != nil {
b.Error(err)
}
}
}
func Benchmark_GOB_Decode1(b *testing.B) {
tmp := AgentService{}
for i := 0; i < b.N*10; i++ {
as.Port = i
GobDecode(asGonBytes, &tmp)
}
}
func Benchmark_GOB_Decode2(b *testing.B) {
tmp := Service{}
for i := 0; i < b.N*10; i++ {
as.Port = i
GobDecode(serviceGonBytes, &tmp)
}
}
執(zhí)行命令:
go test -bench=".*"
測(cè)評(píng)結(jié)果;
$ go test -bench=".*"
Benchmark_STD_Marshal1-4 50000 31224 ns/op
Benchmark_STD_Marshal2-4 30000 49598 ns/op
Benchmark_EASYJSON_STD_Marshal1-4 30000 45778 ns/op
Benchmark_EASYJSON_STD_Marshal2-4 30000 50440 ns/op
Benchmark_EASYJSON_Marshal1-4 100000 14387 ns/op
Benchmark_EASYJSON_Marshal2-4 100000 16009 ns/op
Benchmark_ITERATOR_Marshal1-4 100000 14899 ns/op
Benchmark_ITERATOR_Marshal2-4 100000 21629 ns/op
Benchmark_FFJSON_Marshal1-4 50000 31633 ns/op
Benchmark_FFJSON_Marshal2-4 30000 51668 ns/op
Benchmark_GOB_Encode1-4 20000 97099 ns/op
Benchmark_GOB_Encode2-4 10000 153158 ns/op
Benchmark_STD_Unmarshal1-4 20000 89211 ns/op
Benchmark_STD_Unmarshal2-4 20000 76442 ns/op
Benchmark_EASYJSON_STD_Unmarshal1-4 30000 57695 ns/op
Benchmark_EASYJSON_STD_Unmarshal2-4 20000 66269 ns/op
Benchmark_EASYJSON_Unmarshal1-4 100000 19028 ns/op
Benchmark_EASYJSON_Unmarshal2-4 100000 22035 ns/op
Benchmark_ITERATOR_UnMarshal1-4 50000 35942 ns/op
Benchmark_ITERATOR_UnMarshal2-4 50000 36462 ns/op
Benchmark_FFJSON_UnMarshal1-4 20000 80290 ns/op
Benchmark_FFJSON_UnMarshal2-4 20000 78431 ns/op
Benchmark_GOB_Decode1-4 3000 377698 ns/op
Benchmark_GOB_Decode2-4 3000 463472 ns/op
PASS
ok studygo/jsonbench 49.174s
easyjson
有一個(gè)坑,從代碼中可以看到Benchmark_EASYJSON_STD_*
的方法,是因?yàn)閑asyjson生成的代碼中已經(jīng)包含了MarshalJSON
和UnmarshalJSON
方法,那么只要對(duì)這些結(jié)構(gòu)體執(zhí)行json.marshalJSON
和json.UnmarshalJSON
都會(huì)默認(rèn)調(diào)用easyjson生成的方法。本人運(yùn)行多次,都會(huì)發(fā)現(xiàn)調(diào)用easyjson生成的MarshalJSON
方法比標(biāo)準(zhǔn)庫(kù)中的慢一些達(dá)到50%左右,但是調(diào)用easyjson
生成的UnmarshalJSON
比標(biāo)準(zhǔn)庫(kù)的快一些大概20%。easyjson
速度雖然比較快,但也是存在一些不適合的場(chǎng)景,比如如果需要對(duì)interface
接口進(jìn)行序列化時(shí)候。所以建議采用easyjson
與標(biāo)準(zhǔn)庫(kù)結(jié)合。創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國(guó)云服務(wù)器,動(dòng)態(tài)BGP最優(yōu)骨干路由自動(dòng)選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨(dú)有T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動(dòng)現(xiàn)已開啟,新人活動(dòng)云服務(wù)器買多久送多久。