Protobuf简介
Protocal Buffers是谷歌开发的一种数据描述语言,能够将结构化数据序列化,可用于数据存储、通信协议等方面。Protobuf是跨语言的,并且自带了一个编译器(protoc
),只需要用它进行编译,可以编译成Java、python、C++、C#、Go等代码,然后就可以直接使用,不需要再写其他代码,自带有解析的代码。
因此Protobuf的使用非常方便,并且还有一个重要的特点:它比Json格式更快,且占用空间更小。
它的官方网址为:https://github.com/protocolbuffers/protobuf
Protobuf的安装
Protobuf的安装总共分为两步:
- 安装Protobuf的自带编译器:
protoc
- 安装对应语言版本的客户端
Step1:安装Protobuf自带的编译器
Protobuf自带编译器的安装可以自己在本机上通过源代码编译安装,也可以直接下载官方相应的编译好的二进制包,开箱即用。官方编译好的包下载地址为:https://github.com/protocolbuffers/protobuf/releases/tag/v3.7.1
如上图所示,这个页面有各种语言的protobuf包进行下载,分别表示如下:
all
表示所有语言的包,后面cpp
表示C++语言,csharp
表示C#语言- 各语言包之后是各平台编译的二进制包,对应有Linux、MacOS和Windows操作系统的编译结果
- 最后是源码
这里如果下载了相应语言的protobuf包,需要通过编译安装方式进行安装,以Python为例:
1 | 下载相应的python版本:protobuf-python-3.7.1.zip |
如果上面编译报错的话,可能需要升级gcc的版本:
1 | yum install centos-release-scl -y |
同时还需要注意的是,上面实际上既编译安装了protobuf的编译器protoc,又安装了protobuf的python语言客户端。
还有一点非常重要:安装python语言客户端的时候,如果没有指定--cpp_implementation
这个参数,那么安装的是纯python版本
的解析器,这个解析速度并不快,甚至比json还要慢,因此安装的时候一定要带这个参数,相当于是以C++的运行时来解析protobuf格式的数据,会比纯python方式快10
倍以上。
如果这里不想自己编译,那就直接下载官方编译好的包:
1 | 下载官方编译好的包 |
此时,进入bin
目录下就可以看到已经编译好的protoc
可执行文件了。
Step2:安装Protobuf语言客户端
安装python的客户端,直接用pip
命令即可安装:
1 | sudo /usr/local/bin/pip3 install protobuf |
这里通过pip
命令安装默认是加了--cpp_implementation
C++运行时参数的,注意仅在protobuf 3.2
及以上版本是默认加的,其他旧版本是纯python的,没有加该参数进行优化。
Protobuf的使用
protobuf 2与protobuf 3的语法相差比较大,具体可参考这篇文章。下面以protobuf 3为例进行说明。
新建proto文件
proto
文件是用来指定数据格式的,示例addressbook.proto
如下:
1 | syntax = "proto3"; |
用protoc编译器生成对应的语言类
输入如下内容,可以看到如下结果:1
protoc --help
也就是说通过这个二进制的可执行命令可以将前面定义的数据格式addressbook.proto
生成各种语言的引用包。
1 | 在当前目录下生成addressbook.proto对应的python格式的引用文件 |
可以看到在当前文件夹下面生成了一个addressbook_pb2.py
文件,后面在python程序中引用这个文件,就可以进行相应的序列化和反序列化操作了。
需要注意的是,protoc编译器的版本与相应语言解析protobuf的客户端版本最好一致,不然会有一些莫名的bug。
Protobuf与Json性能的比较
性能比较采用的工具是line_profiler
,它可以逐行打印函数每一行运行所花费的时间。
安装该工具:1
sudo /usr/local/bin/pip3 install line_profiler
然后写测试脚本test.py
如下:
1 | import json |
输入如下命令执行该脚本:
1 | kernprof -l -v test.py |
得到结果如下:
可以看到无论是序列化还是反序列化,protobuf都比json快5
倍左右。
Protobuf使用注意事项
如果定义了两个proto文件,里面写的是同样的package,且有同样的变量名,那么在python同时引用这两个pb2.py文件的时候会报错。
例如再新建一个addressbook1.proto
文件,内容如下:
1 | syntax = "proto3"; |
同样
1 | protoc --python_out=. addressbook1.proto |
生成一个addressbook1_pb2.py
文件。在python中同时引用这两个文件,会报错如下:
解决办法是:如果有两个proto文件里面有相同的变量名,在package里面写不一样的包名即可。这样重新生成的pb2.py文件,再同时引用的时候就不会报错了:
【版权声明】
本文首发于戚名钰的博客,欢迎转载,但是必须保留本文的署名戚名钰(包含链接)。如您有任何商业合作或者授权方面的协商,请给我留言:qimingyu.security@foxmail.com
欢迎关注我的微信公众号:科技锐新
本文永久链接:http://qimingyu.github.io/2019/05/02/Protobuf的使用及性能对比测试/