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

2018年04月18日 14:02:24 疯疯癫癫 阅读数:2644
 
 版权声明:本文为博主原创文章,未经博主允许不得转载。 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 文件

写在最后

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

 

Golang 序列化方式及对比的更多相关文章

  1. .net 各种序列化方式效率对比

    在服务与服务之间传输的是二进制数据,而在此之前有多种方法将数据内容进行序列化来减小数据传递大小,现针对于目前主流的几种序列化方式做了简单数据统计对比. 先做下简单介绍↓↓↓ 1.protobuf-ne ...

  2. springboot系列十一、redisTemplate和stringRedisTemplate对比、redisTemplate几种序列化方式比较

    一.redisTemplate和stringRedisTemplate对比 RedisTemplate看这个类的名字后缀是Template,如果了解过Spring如何连接关系型数据库的,大概不会难猜出 ...

  3. [java]序列化框架性能对比(kryo、hessian、java、protostuff)

    序列化框架性能对比(kryo.hessian.java.protostuff) 简介:   优点 缺点 Kryo 速度快,序列化后体积小 跨语言支持较复杂 Hessian 默认支持跨语言 较慢 Pro ...

  4. python笔记-20 django进阶 (model与form、modelform对比,三种ajax方式的对比,随机验证码,kindeditor)

    一.model深入 1.model的功能 1.1 创建数据库表 1.2 操作数据库表 1.3 数据库的增删改查操作 2.创建数据库表的单表操作 2.1 定义表对象 class xxx(models.M ...

  5. 深入浅出爬虫之道: Python、Golang与GraphQuery的对比

    深入浅出爬虫之道: Python.Golang与GraphQuery的对比 本文将分别使用 Python ,Golang 以及 GraphQuery 来解析某网站的 素材详情页面 ,这个页面的特色是具 ...

  6. 【转】几种Java序列化方式的实现

    0.前言 本文主要对几种常见Java序列化方式进行实现.包括Java原生以流的方法进行的序列化.Json序列化.FastJson序列化.Protobuff序列化. 1.Java原生序列化 Java原生 ...

  7. Redis 序列化方式StringRedisSerializer、FastJsonRedisSerializer和KryoRedisSerializer

    当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的.RedisTemplate默认使用的是JdkSerializat ...

  8. 序列化框架性能对比(kryo、hessian、java、protostuff)

    简介:   优点 缺点 Kryo 速度快,序列化后体积小 跨语言支持较复杂 Hessian 默认支持跨语言 较慢 Protostuff 速度快,基于protobuf 需静态编译 Protostuff- ...

  9. Android进程通信之一:两种序列化方式

    2月下旬辞职了,去海南度假到现在,领略了一把三亚风情也算任性和 然而这样任性带来的后果就是..不行了我必须吐槽一句.. 没毕业的找工作就这么难嘛!投了57家一家面试机会都没有,好歹给个面试机会啊!!本 ...

随机推荐

  1. ios开发之 -- NSData 和 NSString , UIImage 等之间的互转

    //NSData转换为UIImage NSData *imageData = [NSData dataWithContentsOfFile: imagePath]; UIImage *image = ...

  2. ios开发之--通过通知监听textfield的输入状态,判断按钮的状态

    第一步: _rightBtn = [UIButton buttonWithType:UIButtonTypeCustom]; _rightBtn.frame = CGRectMake(kWidth - ...

  3. CreateProcess函数详解

    在windows程序设计五中有详解 CreateProcess 说明: WIN32API函数CreateProcess用来创建一个新的进程和它的主线程,这个新进程运行指定的可执行文件. 函数原型: B ...

  4. Jackson(ObjectMapper)的简单使用(可转xml)

    参考文章:http://www.cnblogs.com/hoojo/archive/2011/04/22/2024628.html  (原文章更详细哦,且有介绍xml与java对象的互转) 参考文章作 ...

  5. Linux 添用户报错:useradd:警告:此主目录已经存在

    建立mysql用户.组 groupadd mysql useradd -g mysql mysql 然后删除 userdel mysql 再添用户和组加时,提示: 解决方法:删除用户不用userdel ...

  6. Linux应急响应(三):挖矿病毒

    0x00 前言 ​ 随着虚拟货币的疯狂炒作,利用挖矿脚本来实现流量变现,使得挖矿病毒成为不法分子利用最为频繁的攻击方式.新的挖矿攻击展现出了类似蠕虫的行为,并结合了高级攻击技术,以增加对目标服务器感染 ...

  7. Waf-Bypass-Learning

    WAF Bypass 综合篇: WAF攻防研究之四个层次Bypass WAF Bypass WAF Cookbook - MayIKissYou My Waf Bypass Series Articl ...

  8. Linux ab 命令

    ab 是一个性能测试工具,用来测试一个页面每秒钟能处理多少HTTP请求 [root@localhost ~]$ yum install -y httpd-tools # 安装ab工具 [root@lo ...

  9. SVN设置没有写log不能commit

    操作方法:在SVN的Repositories下,找到要配置的项目,在项目目录下找到hooks文件夹,在其下创建pre-commit.bat文件,把下面复制进去就可以了(无需重启,如果改动,保存bat文 ...

  10. [Command] lrzsz - 文件传输工具包

    lrzsz 是一个支持 XMODEM.YMODEM.ZMODEM 文件传输协议的 Unix 程序包.它是 Omen Technologies 公司所有的 rzsz 程序包的公开发行增强版,遵守 GNU ...