您的位置:

GO Protobuf实现消息序列化和反序列化的高效性

一、Protobuf简介

Protocol Buffers(简称Protobuf)是Google开源的一种轻便高效的序列化数据结构的方法,由Google基于一种二进制协议实现,通过源代码编译器生成源代码,具有良好的跨语言性。Protobuf可以生成Java、C++、Python等语言的源代码,且序列化后的数据大小非常的小, 这种方式比XML快许多倍,同时也比JSON快。

二、Protobuf的使用

Protobuf结构体定义包含name,tag和type三个成员,其中name表示结构体成员名称,tag表示用整形表示的序号,type表示结构体成员数据类型。

syntax = "proto3";
package example;
message Person {
    string name = 1;
    int32 age = 2;
    string address = 3;
}

在GO中使用Protobuf,首先需要安装Protobuf。

go get -u github.com/golang/protobuf/proto

使用Protobuf需要创建.proto文件并且定义好结构体,然后使用protoc编译器将.proto文件编译成目标语言的源代码文件。

//编译.proto文件
protoc --go_out=. person.proto

Protobuf提供了基本的Marshal和Unmarshal方法来进行序列化与反序列化操作。

package main

import (
    "github.com/golang/protobuf/proto"
    "example"
)

func main() {
    // 创建结构体实例
    p1 := &example.Person{
        Name:    "John",
        Age:     30,
        Address: "New York",
    }
    // 序列化
    data, err := proto.Marshal(p1)
    if err != nil {
        log.Fatal("marshaling error: ", err)
    }
    // 反序列化
    p2 := &example.Person{}
    err = proto.Unmarshal(data, p2)
    if err != nil {
        log.Fatal("unmarshaling error: ", err)
    }
    // p1 and p2 should contain the same data.
    fmt.Println("p1:", p1)
    fmt.Println("p2:", p2)
}

三、Protobuf的高效性

1、数据大小

与JSON数据格式相比,Protobuf序列化后的数据更小,可以将数据传输的时间和成本的最小化。

//结构体定义
message Example {
    string field_one = 1;
    int32 field_two = 2;
    bool field_three = 3;
}
//JSON格式的数据大小
{
    "field_one": "Hello World!",
    "field_two": 12345,
    "field_three": true
} 
//Protobuf格式的数据大小
data: 0a0c48656c6c6f20576f726c642109

2、效率

使用Protobuf进行序列化和反序列化操作的效率非常高。下面是一个比较序列化和反序列化操作的时间使用情况的代码片段

p1 := &example.Person{
        Name:    "John",
        Age:     30,
        Address: "New York",
}
// Marshal the data and record the time it takes to do so.
start := time.Now()
data, err := proto.Marshal(p1)
elapsed := time.Since(start)
fmt.Printf("protobuf marshaling time elapsed: %s\n", elapsed)

在大规模数据的情况下,使用Protobuf所节省的时间和资源是非常可观的。

四、总结

GO Protobuf实现消息序列化和反序列化的高效性使得它成为了一种高效且便于扩展性的数据交换方式。而且,由于Protobuf的良好跨语言特性,它可以轻松地在多种不同平台和语言之间交换数据。

完整代码示例

syntax = "proto3";
package example;
message Person {
    string name = 1;
    int32 age = 2;
    string address = 3;
}


package main

import (
    "fmt"
    "github.com/golang/protobuf/proto"
    "log"
    "time"
    "example"
)

func main() {
    // test protobuf encoding and decoding for example.Person
    p1 := &example.Person{
        Name:    "John",
        Age:     30,
        Address: "New York",
    }
    // Marshal the data.
    start := time.Now()
    data, err := proto.Marshal(p1)
    elapsed := time.Since(start)
    fmt.Printf("protobuf marshaling time elapsed: %s\n", elapsed)
    if err != nil {
        log.Fatal("marshaling error: ", err)
    }

    // Display the raw protobuf bytes.
    fmt.Printf("raw Protobuf bytes: %q\n", data)

    // Unmarshal the data back into a person struct.
    p2 := &example.Person{}
    start = time.Now()
    err = proto.Unmarshal(data, p2)
    elapsed = time.Since(start)
    fmt.Printf("protobuf unmarshaling time elapsed: %s\n", elapsed)
    if err != nil {
        log.Fatal("unmarshaling error: ", err)
    }

    // Display the original and unmarshaled structs.
    fmt.Println("Original struct  :", p1)
    fmt.Println("Unmarshaled struct:", p2)
}