這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
序列化庫在網路傳輸,RPC,資料庫訪問等環境中經常用到,它的效能的好壞直接影響著整個產品的效能。
本文列出了幾種高效能的Go語言的序列化庫,並通過一個簡單的無循環參考的資料結構測試它們的效能。
測試代碼: gosercomp at github
03/14/2016 更新。 增加Thrift/Avro/Gencode的效能比較。
測試的 Serializers
以golang內建的encoding/json和encoding/xml為基準,測試以下效能比較好的幾種序列化庫。
- encoding/json
- encoding/xml
- github.com/youtube/vitess/go/bson
- github.com/tinylib/msgp
- github.com/golang/protobuf
- github.com/gogo/protobuf
- github.com/google/flatbuffers
- Apache/Thrift
- Apache/Avro
排除的 Serializers
基於 alecthomas 已有的測試,下面的庫由於效能的原因沒有進行測試。
- encoding/gob
- github.com/alecthomas/binary
- github.com/davecgh/go-xdr/xdr
- github.com/ugorji/go/codec
- labix.org/v2/mgo/bson
- github.com/DeDiS/protobuf
- gopkg.in/vmihailenco/msgpack.v2
測試環境
add ./bin
into the PATH
environment variable.
- 對於
github.com/youtube/vitess/go/bson
,你可能需要安裝 goimports
和codegen
:
1234 |
go get github.com/youtube/vitess/go/bsongo get golang.org/x/tools/cmd/goimportsgo get github.com/youtube/vitess/tree/master/go/cmd/bsongenbsongen -file data.go -o bson_data.go -type ColorGroup |
- 對於
MessagePack
,你需要安裝庫以及利用go generate
產生相關的類:
12 |
go get github.com/tinylib/msgpgo generate |
- 對於
ProtoBuf
,你需要安裝protoc編譯器,以及protoc庫以及產生相關的類:
123 |
go get github.com/golang/protobuf/protogo get github.com/golang/protobuf/protoc-gen-gogo generate |
- 對於
gogo/protobuf
,你需要安裝庫以及產生相關的類:
123 |
go get github.com/gogo/protobuf/gogoprotogo get github.com/gogo/protobuf/protoc-gen-gofastgo generate |
- 對於
flatbuffers
,你需要安裝thrift編譯器, 以及flatbuffers庫:
12 |
go get github.com/google/flatbuffers/gogo generate |
- 對於
thrift
,你需要安裝flatbuffers編譯器, 以及thrift庫:
12 |
go get git.apache.org/thrift.git/lib/go/thriftgo generate |
12 |
go get github.com/linkedin/goavrogo generate |
- 對於
gencode
,你需要安裝gencode庫,並使用gencode庫的工具產生資料對象:
12 |
go get github.com/andyleap/gencodebin\gencode.exe go -schema=gencode.schema -package gosercomp |
事實上,這裡通過go generate
產生相關的類,你也可以通過命令列產生,請參考data.go
中的注釋。 但是你需要安裝相關的工具,如Thrift,並把它們加入到環境變數Path中
運行下面的命令測試:
1 |
go test -bench=. -benchmem |
測試資料
所有的測試基於以下的struct,自動產生的struct, 比如protobuf也和此結構基本一致。
12345 |
type ColorGroup struct { ID int `json:"id" xml:"id,attr""` Name string `json:"name" xml:"name"` Colors []string `json:"colors" xml:"colors"`} |
效能測試結果
以下效能的測試結果是在我的T430u/Windows 10上的測試結果。
1234567891011121314151617181920212223242526272829303132 |
benchmark _name iter time/iter alloc bytes/iter allocs/iter-------------------------------------------------------------------------------------------------------------------------BenchmarkMarshalByJson-4 1000000 1795 ns/op 376 B/op 4 allocs/opBenchmarkUnmarshalByJson-4 500000 3927 ns/op 296 B/op 9 allocs/opBenchmarkMarshalByXml-4 200000 8216 ns/op 4801 B/op 12 allocs/opBenchmarkUnmarshalByXml-4 50000 26284 ns/op 2807 B/op 67 allocs/opBenchmarkMarshalByBson-4 500000 3258 ns/op 1248 B/op 14 allocs/opBenchmarkUnmarshalByBson-4 1000000 1433 ns/op 272 B/op 7 allocs/opBenchmarkMarshalByMsgp-4 5000000 259 ns/op 80 B/op 1 allocs/opBenchmarkUnmarshalByMsgp-4 3000000 466 ns/op 32 B/op 5 allocs/opBenchmarkMarshalByProtoBuf-4 2000000 955 ns/op 328 B/op 5 allocs/opBenchmarkUnmarshalByProtoBuf-4 1000000 1571 ns/op 400 B/op 11 allocs/opBenchmarkMarshalByGogoProtoBuf-4 10000000 224 ns/op 48 B/op 1 allocs/opBenchmarkUnmarshalByGogoProtoBuf-4 2000000 828 ns/op 144 B/op 8 allocs/opBenchmarkMarshalByFlatBuffers-4 3000000 626 ns/op 16 B/op 1 allocs/opBenchmarkUnmarshalByFlatBuffers-4 100000000 10.4 ns/op 0 B/op 0 allocs/opBenchmarkUnmarshalByFlatBuffers_withFields-4 3000000 493 ns/op 32 B/op 5 allocs/opBenchmarkMarshalByThrift-4 2000000 840 ns/op 64 B/op 1 allocs/opBenchmarkUnmarshalByThrift-4 1000000 1575 ns/op 96 B/op 6 allocs/opBenchmarkMarshalByAvro-4 1000000 1330 ns/op 133 B/op 7 allocs/opBenchmarkUnmarshalByAvro-4 200000 7036 ns/op 1680 B/op 63 allocs/opBenchmarkMarshalByGencode-4 20000000 66.2 ns/op 0 B/op 0 allocs/opBenchmarkUnmarshalByGencode-4 5000000 258 ns/op 32 B/op 5 allocs/op |
多次測試結果差不多。 從結果上上來看, MessagePack,gogo/protobuf,和flatbuffers差不多,這三個優秀的庫在序列化和還原序列化上各有千秋,而且都是跨語言的。 從便利性上來講,你可以選擇MessagePack和gogo/protobuf都可以,兩者都有大廠在用。 flatbuffers有點反人類,因為它的操作很底層,而且從結果上來看,序列化的效能要差一點。但是它有一個好處,那就是如果你只需要特定的欄位, 你無須將所有的欄位都還原序列化。從結果上看,不還原序列化欄位每個調用只用了9.54納秒,這是因為欄位只有在被訪問的時候才從byte數組轉化為相應的類型。 因此在特殊的情境下,它可以提高N被的效能。但是序列化的代碼的面相太難看了。
新增加了gencode的測試,它表現相當出色,而且產生的位元組也非常的小。
官方的Protobuf是通過反射(reflect)實現序列化還原序列化的,所以效率不是很高。而gogo/protobuf則是在代碼產生的時候提供了Marshal/UnMarshal的方法,它不採用反射的方式,所以效能上比官方的庫要好很多。