zoukankan      html  css  js  c++  java
  • Golang 序列化方式及对比

    Golang 序列化方式及对比 - fengfengdiandia的专栏 - CSDN博客 https://blog.csdn.net/fengfengdiandia/article/details/79986237

     版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fengfengdiandia/article/details/79986237

    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(bytes.Buffer)
    
        if err := binary.Write(buf, binary.LittleEndian, m1); err != nil {
            log.Fatal("binary write error:", err)
        }
    
        var m2 Message
        if err := binary.Read(buf, binary.LittleEndian, &m2); err != nil {
            log.Fatal("binary read error:", err)
        }
    }

    注意: 如果字段中有不确定大小的类型,如 int,slice,string 等,则会报错。 
    binary write error:binary.Write: invalid type main.Message

    下面是binary.Write的函数说明:

    // Data must be a fixed-size value or a slice of fixed-size values.
    func Write(w io.Writer, 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 bytes.Buffer
    
        enc := gob.NewEncoder(&buf)
        dec := gob.NewDecoder(&buf)
    
        if err := enc.Encode(m1); err != nil {
            log.Fatal("encode error:", err)
        }
    
        var m2 Message2
        if err := dec.Decode(&m2); err != nil {
            log.Fatal("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 = json.Marshal(m1); err != nil {
            log.Fatal("json marshal error:", err)
        }
    
        var m2 Message2
        if err = json.Unmarshal(buf, &m2); err != nil {
            log.Fatal("json unmarshal error:", err)
        }
    }

    四. Protobuf

    当然,还可以使用 protobuf 来序列化.

    test.proto

    syntax = "proto2";
    package example;
    
    message Message {
        required uint64 id = 1;
        required uint64 size = 2;
        required string data = 3;
    }
    func ProtoEncodeDecode() {
        m1 := &example.Message{
            Id:   proto.Uint64(4),
            Size: proto.Uint64(1024),
            Data: proto.String("proto"),
        }
    
        buf, err := proto.Marshal(m1)
        if err != nil {
            log.Fatal("proto marshal error:", err)
        }
    
        var m2 example.Message
        if err = proto.Unmarshal(buf, &m2); err != nil {
            log.Fatal("proto unmarshal error:", err)
        }
        fmt.Println(m2.GetId(), m2.GetSize(), m2.GetData())
    }

    五. BenchMark 对比

    现在来对比下这几种序列化方式的性能。

    目录结构:

    $ tree serialize
    serialize
    ├── serialize.go
    ├── serialize_test.go
    └── example
        ├── test.pb.go
        └── test.proto

    serialize.go

    package serialize
    
    import (
        "bytes"
        "encoding/binary"
        "encoding/gob"
        "encoding/json"
        "log"
        "serialize/example"
    
        "github.com/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(bytes.Buffer)
    
        if err := binary.Write(buf, binary.LittleEndian, m1); err != nil {
            log.Fatal("binary write error:", err)
        }
    
        var m2 Message
        if err := binary.Read(buf, binary.LittleEndian, &m2); err != nil {
            log.Fatal("binary read error:", err)
        }
    }
    
    func GobEncodeDecode() {
        m1 := Message2{2, 1024, "gob"}
        var buf bytes.Buffer
    
        enc := gob.NewEncoder(&buf)
        dec := gob.NewDecoder(&buf)
    
        if err := enc.Encode(m1); err != nil {
            log.Fatal("encode error:", err)
        }
    
        var m2 Message2
        if err := dec.Decode(&m2); err != nil {
            log.Fatal("decode error:", err)
        }
    }
    
    func JsonEncodeDecode() {
        m1 := Message2{3, 1024, "json"}
        var buf []byte
        var err error
    
        if buf, err = json.Marshal(m1); err != nil {
            log.Fatal("json marshal error:", err)
        }
    
        var m2 Message2
        if err = json.Unmarshal(buf, &m2); err != nil {
            log.Fatal("json unmarshal error:", err)
        }
    }
    
    func ProtoEncodeDecode() {
        m1 := &example.Message{
            Id:   proto.Uint64(4),
            Size: proto.Uint64(1024),
            Data: proto.String("proto"),
        }
    
        buf, err := proto.Marshal(m1)
        if err != nil {
            log.Fatal("proto marshal error:", err)
        }
    
        var m2 example.Message
        if err = proto.Unmarshal(buf, &m2); err != nil {
            log.Fatal("proto unmarshal error:", err)
        }
    }

    serialize_test.go

    package serialize
    
    import (
        "testing"
    )
    
    func BenchmarkBinaryRW(b *testing.B) {
        for i := 0; i < b.N; i++ {
            BinaryRW()
        }
    }
    
    func BenchmarkGobEncodeDecode(b *testing.B) {
        for i := 0; i < b.N; i++ {
            GobEncodeDecode()
        }
    }
    
    func BenchmarkJsonEncodeDecode(b *testing.B) {
        for i := 0; i < b.N; i++ {
            JsonEncodeDecode()
        }
    }
    
    func BenchmarkProtoEncodeDecode(b *testing.B) {
        for i := 0; i < b.N; 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 支持多种类型,性能高 需要单独存放结构,如果结构变动需要重新生成 .pb.go 文件

    写在最后

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

     
  • 相关阅读:
    Collections类
    delphi Tdxribbon 设置背景和skin 皮肤
    模拟一个带背景的 TPanel
    将控件画成圆角的效果(Delphi)
    Delphi自写组件:可设置颜色的按钮
    delphi StringGrid 表格的复制粘贴
    学习人工智能
    python 环境搭建和Spyder的安装应用
    python 廖雪峰的官方网站
    spyder 安装
  • 原文地址:https://www.cnblogs.com/rsapaper/p/10237583.html
Copyright © 2011-2022 走看看