Golang 序列化的方式:
- Binary
- Gob
- JSON
- Protobuf
一. Binary
// OK
type Message struct {
Id uint64
Size uint64
}
// Wrong
/*type Message struct {
Id int
Size int
Data string
}*/
func BinaryRW() {
m1 := Message{1, 1024}
buf := new()
if err := (buf, , m1); err != nil {
("binary write error:", err)
}
var m2 Message
if err := (buf, , &m2); err != nil {
("binary read error:", err)
}
}
注意: 如果字段中有不确定大小的类型,如 int,slice,string 等,则会报错。
binary write error:: invalid type
下面是的函数说明:
// Data must be a fixed-size value or a slice of fixed-size values.
func Write(w , order ByteOrder, data interface{}) error {
解决办法:
- int 换成 int32 等固定大小的类型
- slice 换成类似 [8]byte 这种固定大小
- 选择其他序列化方式
二. Gob
针对 binary 不能直接使用 string 和 slice 问题,可以使用 gob。
type Message2 struct {
Id uint64
Size uint64
Data string
}
func GobEncodeDecode() {
m1 := Message2{2, 1024, "gob"}
var buf
enc := (&buf)
dec := (&buf)
if err := (m1); err != nil {
("encode error:", err)
}
var m2 Message2
if err := (&m2); err != nil {
("decode error:", err)
}
}
三. JSON
还可以使用 json 传递数据
type Message2 struct {
Id uint64 `json:"id"`
Size uint64 `json:"size"`
Data string `json:"data"`
}
func JsonEncodeDecode() {
m1 := Message2{3, 1024, "json"}
var buf []byte
var err error
if buf, err = (m1); err != nil {
("json marshal error:", err)
}
var m2 Message2
if err = (buf, &m2); err != nil {
("json unmarshal error:", err)
}
}
四. Protobuf
当然,还可以使用 protobuf 来序列化.
syntax = "proto2";
package example;
message Message {
required uint64 id = 1;
required uint64 size = 2;
required string data = 3;
}
func ProtoEncodeDecode() {
m1 := &{
Id: proto.Uint64(4),
Size: proto.Uint64(1024),
Data: ("proto"),
}
buf, err := (m1)
if err != nil {
("proto marshal error:", err)
}
var m2
if err = (buf, &m2); err != nil {
("proto unmarshal error:", err)
}
((), (), ())
}
五. BenchMark 对比
现在来对比下这几种序列化方式的性能。
目录结构:
$ tree serialize
serialize
├── serialize.go
├── serialize_test.go
└── example
├── test.pb.go
└── test.proto
package serialize
import (
"bytes"
"encoding/binary"
"encoding/gob"
"encoding/json"
"log"
"serialize/example"
"/golang/protobuf/proto"
)
type Message struct {
Id uint64
Size uint64
}
type Message2 struct {
Id uint64 `json:"id"`
Size uint64 `json:"size"`
Data string `json:"data"`
}
func BinaryRW() {
m1 := Message{1, 1024}
buf := new()
if err := (buf, , m1); err != nil {
("binary write error:", err)
}
var m2 Message
if err := (buf, , &m2); err != nil {
("binary read error:", err)
}
}
func GobEncodeDecode() {
m1 := Message2{2, 1024, "gob"}
var buf
enc := (&buf)
dec := (&buf)
if err := (m1); err != nil {
("encode error:", err)
}
var m2 Message2
if err := (&m2); err != nil {
("decode error:", err)
}
}
func JsonEncodeDecode() {
m1 := Message2{3, 1024, "json"}
var buf []byte
var err error
if buf, err = (m1); err != nil {
("json marshal error:", err)
}
var m2 Message2
if err = (buf, &m2); err != nil {
("json unmarshal error:", err)
}
}
func ProtoEncodeDecode() {
m1 := &{
Id: proto.Uint64(4),
Size: proto.Uint64(1024),
Data: ("proto"),
}
buf, err := (m1)
if err != nil {
("proto marshal error:", err)
}
var m2
if err = (buf, &m2); err != nil {
("proto unmarshal error:", err)
}
}
serialize_test.go
package serialize
import (
"testing"
)
func BenchmarkBinaryRW(b *) {
for i := 0; i < ; i++ {
BinaryRW()
}
}
func BenchmarkGobEncodeDecode(b *) {
for i := 0; i < ; i++ {
GobEncodeDecode()
}
}
func BenchmarkJsonEncodeDecode(b *) {
for i := 0; i < ; i++ {
JsonEncodeDecode()
}
}
func BenchmarkProtoEncodeDecode(b *) {
for i := 0; i < ; i++ {
ProtoEncodeDecode()
}
}
BenchmarkBinaryRW-4 2000000 609 ns/op
BenchmarkGobEncodeDecode-4 100000 23689 ns/op
BenchmarkJsonEncodeDecode-4 1000000 1889 ns/op
BenchmarkProtoEncodeDecode-4 2000000 778 ns/op
PASS
ok serialize 8.722s
方式 | 优点 | 缺点 |
---|---|---|
binary | 性能高 | 不支持不确定大小类型 int、slice、string |
gob | 支持多种类型 | 性能低 |
json | 支持多种类型 | 性能低于 binary 和 protobuf |
protobuf | 支持多种类型,性能高 | 需要单独存放结构,如果结构变动需要重新生成 . 文件 |
写在最后
注意: 网络传输上面类似数据时,记得要考虑粘包问题。