再測定Golang JSONクラスライブラリ
プロジェクトを書くにはずっとシーケンス化が必要で、聞いて、多くの学生の先生が各golangの
クラスライブラリ
シーケンス番号
クラスライブラリ
アドレス
コメント
1
encoding/json
Golan
2
easyjson
github.com/mailru/easyjson
3
ffjson
github.com/mailru/easyjson
4
iterator/json
github.com/json-iterator/go
主に上記のタイプに対して行い,本人は異なるクラスライブラリに対して異なる構造体(構造体名が異なるだけで,フィールド順序とタイプが同じ)を用いる.
環境
環境はMacBook Pro(Core i 5プロセッサ/8 GBメモリ)go 1.8.3 darwin/amd64
コード#コード#
benchコードは次のとおりです.
コマンドの実行:
評価結果
結論どのクラスライブラリが一番速いですか?答え:評価クラスライブラリの中で一番速いです.速度:easyjson=>iterator=>encoding/json=>ffjson ピットはありますか?答え: はどのように選択しますか?答え:
json
庫を評価しているのを見ました.では、私はどうして今回の評価を続けなければならないのでしょうか.実践した知識が最も説得力があり、自分のものでもあるので、私も本博文の同級生の先生が評価のコードを修正して実行することができることを望んでいます.私は一定の体得があると信じています.今回の評価でクラスライブラリを選択しました.クラスライブラリ
シーケンス番号
クラスライブラリ
アドレス
コメント
1
encoding/json
Golan
2
easyjson
github.com/mailru/easyjson
3
ffjson
github.com/mailru/easyjson
4
iterator/json
github.com/json-iterator/go
主に上記のタイプに対して行い,本人は異なるクラスライブラリに対して異なる構造体(構造体名が異なるだけで,フィールド順序とタイプが同じ)を用いる.
環境
環境はMacBook Pro(Core i 5プロセッサ/8 GBメモリ)go 1.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)
}
}
コマンドの実行:
go test -bench=".*"
評価結果
$ 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
は、easyjsonが生成したコードにBenchmark_EASYJSON_STD_*
およびMarshalJSON
の方法が含まれているため、コードからUnmarshalJSON
の方法が見られるピットがあり、これらの構造体に対してjson.marshalJSON
およびjson.UnmarshalJSON
を実行すると、easyjson生成の方法がデフォルトで呼び出される.本人が何度も実行すると,easyjson生成を呼び出すMarshalJSON
メソッドは標準ライブラリの中のものより50%程度遅いが,easyjson
生成を呼び出すUnmarshalJSON
は標準ライブラリのものより約20%速いことが分かった.easyjson
速度は比較的速いが、interface
インタフェースをシーケンス化する必要がある場合など、不適切なシーンもある.したがって、easyjson
を標準ライブラリと組み合わせることをお勧めします.