⚡️ Golang Serializer Benchmark Comparison
Go Other
Latest commit 6de4290 Jan 3, 2017 @smallnest fix #6

README.md

Golang 序列化反序列化库的性能比较

测试的 Serializers

以golang自带的encoding/jsonencoding/xml为基准,测试以下性能比较好的几种序列化库。

排除的 Serializers

基于 alecthomas 已有的测试,下面的库由于性能的原因没有进行测试。

测试环境

go version: 1.7.4

  • 对于 MessagePack,你需要安装库以及利用go generate生成相关的类:

    go get github.com/tinylib/msgp
    go generate
  • 对于ProtoBuf,你需要安装protoc编译器,以及protoc库以及生成相关的类:

    go get github.com/golang/protobuf
    go generate
  • 对于gogo/protobuf,你需要安装库以及生成相关的类:

    go get github.com/gogo/protobuf/gogoproto
    go get -u github.com/gogo/protobuf/protoc-gen-gogofaster
    go generate
  • 对于flatbuffers,你需要安装[flatbuffers编译器](https://github.com/google/flatbuffers/releases, 以及flatbuffers库:

    go get github.com/google/flatbuffers/go
    go generate
  • 对于thrift,), 你需要安装thrift编译器以及thrift库:

    go get git.apache.org/thrift.git/lib/go/thrift
    go generate
  • 对于Avro,你需要安装goavro库:

    go get github.com/linkedin/goavro
    go generate
  • 对于gencode,你需要安装gencode库,并使用gencode库的工具产生数据对象:

    go get github.com/andyleap/gencode
    bin\gencode.exe go -schema=gencode.schema -package gosercomp

    gencode也是一个高性能的编解码库,提供了代码生成工具,而且产生的数据非常的小。

  • 对于zebraPack,你需要安装zebraPack库,并使用zebraPack工具产生数据对象:

    go get github.com/glycerine/zebrapack
    go generate zebrapack_data.go 
  • 对于ugorji/go/codec,你需要安装代码生成工具和codec库:

  go get -tags=unsafe  -u github.com/ugorji/go/codec/codecgen
  go get -tags=unsafe -u github.com/ugorji/go/codec

  codecgen.exe -o data_codec.go data.go

ugorji/go/codec是一个高性能的编解码框架,支持 msgpack、cbor、binc、json等格式。本测试中测试了 cbor 和 msgpack的编解码,可以和上面的 tinylib/msgp框架进行比较。

事实上,这里通过go generate生成相关的类,你也可以通过命令行生成,请参考data.go中的注释。 但是你需要安装相关的工具,如Thrift,并把它们加入到环境变量Path中

运行下面的命令测试:

go test -bench=. -benchmem

测试数据

所有的测试基于以下的struct,自动生成的struct, 比如protobuf也和此结构基本一致。

type ColorGroup struct {
    ID     int `json:"id" xml:"id,attr""`
    Name   string `json:"name" xml:"name"`
    Colors []string `json:"colors" xml:"colors"`
}
`

性能测试结果

BenchmarkMarshalByJson-4                         1000000              1375 ns/op             376 B/op          4 allocs/op
BenchmarkUnmarshalByJson-4                        500000              2849 ns/op             296 B/op          9 allocs/op

BenchmarkMarshalByXml-4                           300000              5323 ns/op            4801 B/op         12 allocs/op
BenchmarkUnmarshalByXml-4                         100000             18414 ns/op            2807 B/op         67 allocs/op

BenchmarkMarshalByMsgp-4                        10000000               128 ns/op              80 B/op          1 allocs/op
BenchmarkUnmarshalByMsgp-4                       5000000               320 ns/op              32 B/op          5 allocs/op

BenchmarkMarshalByProtoBuf-4                     2000000               608 ns/op             328 B/op          5 allocs/op
BenchmarkUnmarshalByProtoBuf-4                   1000000              1049 ns/op             400 B/op         11 allocs/op

BenchmarkMarshalByGogoProtoBuf-4                10000000               133 ns/op              48 B/op          1 allocs/op
BenchmarkUnmarshalByGogoProtoBuf-4               3000000               544 ns/op             144 B/op          8 allocs/op

BenchmarkMarshalByFlatBuffers-4                  3000000               438 ns/op              16 B/op          1 allocs/op
BenchmarkUnmarshalByFlatBuffers-4               300000000                4.68 ns/op            0 B/op          0 allocs/op
BenchmarkUnmarshalByFlatBuffers_withFields-4    10000000               162 ns/op               0 B/op          0 allocs/op

BenchmarkMarshalByThrift-4                       2000000               654 ns/op              64 B/op          1 allocs/op
BenchmarkUnmarshalByThrift-4                     1000000              1810 ns/op             656 B/op         11 allocs/op

BenchmarkMarshalByAvro-4                         1000000              1167 ns/op             133 B/op          7 allocs/op
BenchmarkUnmarshalByAvro-4                        300000              4199 ns/op            1680 B/op         63 allocs/op

BenchmarkMarshalByGencode-4                     30000000                41.8 ns/op             0 B/op          0 allocs/op
BenchmarkUnmarshalByGencode-4                   10000000               199 ns/op              32 B/op          5 allocs/op

BenchmarkMarshalByCodecAndCbor-4                 2000000               940 ns/op             239 B/op          2 allocs/op
BenchmarkUnmarshalByCodecAndCbor-4              10000000               223 ns/op               0 B/op          0 allocs/op

BenchmarkMarshalByCodecAndMsgp-4                 2000000              1097 ns/op             239 B/op          2 allocs/op
BenchmarkUnmarshalByCodecAndMsgp-4              10000000               239 ns/op               0 B/op          0 allocs/op

BenchmarkMarshalByGoMemdump-4                     200000              8577 ns/op            1564 B/op         31 allocs/op
BenchmarkUnmarshalByGoMemdump-4                  3000000               559 ns/op             112 B/op          5 allocs/op

BenchmarkMarshalByColfer-4                      20000000                84.9 ns/op            48 B/op          1 allocs/op
BenchmarkUnmarshalByColfer-4                     5000000               282 ns/op              96 B/op          6 allocs/op

BenchmarkMarshalByZebrapack-4                   20000000               128 ns/op             132 B/op          0 allocs/op
BenchmarkUnmarshalByZebrapack-4                 10000000               177 ns/op               0 B/op          0 allocs/op

多次测试结果差不多。 从结果上上来看, MessagePack,gogo/protobuf,和flatbuffers差不多,这三个优秀的库在序列化和反序列化上各有千秋,而且都是跨语言的。 从便利性上来讲,你可以选择MessagePackgogo/protobuf都可以,两者都有大厂在用。 flatbuffers有点反人类,因为它的操作很底层,而且从结果上来看,序列化的性能要差一点。但是它有一个好处,那就是如果你只需要特定的字段, 你无须将所有的字段都反序列化。从结果上看,不反序列化字段每个调用只用了9.54纳秒,这是因为字段只有在被访问的时候才从byte数组转化为相应的类型。 因此在特殊的场景下,它可以提高N被的性能。但是序列化的代码的面相太难看了。

新增加了gencode的测试,它表现相当出色,而且生成的字节也非常的小。

Codec的Unmarshal性能不错,但是Marshal性能不是太好。

colfer的性能也不错,它能够跨Go,Java, Javascript平台。

新加入的zebrapack性能抢眼,不但性能卓越,而且可以实现zero allocation,值得关注。