Golang 序列化方式及对比

时间:2025-03-08 07:49:33

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 支持多种类型,性能高 需要单独存放结构,如果结构变动需要重新生成 . 文件

写在最后

注意: 网络传输上面类似数据时,记得要考虑粘包问题。