项目笔记之 protobuf | ⻘训营笔记

87 阅读2分钟

这是我参与「第五届⻘训营 」笔记创作活动的第7天。

这篇文章介绍一下项目中关于protobuf的使用。由于项目说明中给了接口的proto定义,于是可以利用protoc-gen-go工具来根据接口生成代码,可以统一接口定义实现。

protobuf 介绍

protobuf 即 Protocol Buffers,是一种轻便高效的结构化数据存储格式,与语言、平台无关,可扩展可序列化。protobuf 性能和效率大幅度优于 JSON、XML 等其他的结构化数据格式。protobuf 是以二进制方式存储的,占用空间小,但也带来了可读性差的缺点。protobuf 在通信协议和数据存储等领域应用广泛。

Protobuf 在 .proto 定义需要处理的结构化数据,可以通过 protoc 工具,将 .proto 文件转换为 C、C++、Golang、Java、Python 等多种语言的代码,兼容性好,易于使用。

安装

protoc

$ brew install protobuf
$ protoc --version
libprotoc x.x.x

当然也可以源码安装。

protoc-gen-go

我们需要在 Golang 中使用 protobuf,还需要安装 protoc-gen-go,这个工具用来将 .proto 文件转换为 Golang 代码。

go get -u github.com/golang/protobuf/protoc-gen-go

使用

以项目给定的proto文件为例子。

syntax = "proto2";
package douyin.core;
option go_package = "./core;core";

message User {
  required int64 id = 1; // 用户id
  required string name = 2; // 用户名称
  optional int64 follow_count = 3; // 关注总数
  optional int64 follower_count = 4; // 粉丝总数
  required bool is_follow = 5; // true-已关注,false-未关注
  optional string avatar = 6; //用户头像
  optional string background_image = 7; //用户个人页顶部大图
  optional string signature = 8; //个人简介
  optional int64 total_favorited = 9; //获赞数量
  optional int64 work_count = 10; //作品数量
  optional int64 favorite_count = 11; //点赞数量
}

此时项目文件结构如下

.
├── go.mod
├── go.sum
├── main.go
└── pb
    └──basic_api.proto

在pb目录使用命令 protoc --go_out=. *.proto

生成代码,为User的model代码,此代码可以用于序列化和反序列化传递。

.
├── go.mod
├── go.sum
├── main.go
└── pb
    ├── basic_api.proto
    └── core
        └── basic_api.pb.go

测试

在main.go中进行User的序列化与反序列化测试,

package main

import (
	"dousheng/pb/core"
	"log"

	"google.golang.org/protobuf/proto"
)

func main() {
	var id int64
	test := &core.User{
		Id:              &id,
		Name:            new(string),
		FollowCount:     new(int64),
		FollowerCount:   new(int64),
		IsFollow:        new(bool),
		Avatar:          new(string),
		BackgroundImage: new(string),
		Signature:       new(string),
		TotalFavorited:  new(int64),
		WorkCount:       new(int64),
		FavoriteCount:   new(int64),
	}
	//序列化
	data, err := proto.Marshal(test)
	if err != nil {
		log.Fatal("proto encode error: ", err)
		return
	}

	//反序列化
	newTest := &core.User{}
	err = proto.Unmarshal(data, newTest)
	if err != nil {
		log.Fatal("proto decode error: ", err)
		return
	}

	if test.GetId() != newTest.GetId() {
		log.Fatalf("data mismatch id %d != %d", test.GetId(), newTest.GetId())
		return
	} else {
		log.Println("data matched!")
	}

}

结果如下

2023/01/20 23:41:48 data matched!

结论

可以看到,使用工具可以大大提高代码效率,毕竟很多基础的代码不用自己写了,可以集中更多精力在业务流程之上。使用protobuf也比使用json传递数据效率更高,可以提高系统性能。

之后的项目中会将protobuf和grpc一起使用,使用proto文件生成可以用于rpc调用的代码,之后会写一篇文章说明。