Protocol Buffers + Python 实践(1)

最近有个东西, 需要将大量数据通过公网(物理上)传递到另外一台服务器, 之前采用JSON格式. 月均流量1T, 考虑到目前VPS大多数都是双向计费, 所以实际上成本居高不下.

JSON&MsgPack

玩赛马娘的时候了解到赛马娘服务器和客户端传递的是MsgPack, 首先先介绍MsgPack.

import json  # 导入json库
import msgpack # 导入msgpack包, 可以通过 pip install msgpack 安装

data = {"message": "测试消息!", "code": 0, "error": None}
data_json = json.dumps(data)
data_msgpack = msgpack.dumps(data)
print(data_json)
# {"message": "\u6d4b\u8bd5\u6d88\u606f!", "code": 0, "error": null}
print(data_msgpack)
# msgpack
# b'\x83\xa7message\xad\xe6\xb5\x8b\xe8\xaf\x95\xe6\xb6\x88\xe6\x81\xaf!\xa4code\x00\xa5error\xc0'

# 比较大小
print(len(data_json.encode('utf-8')), len(data_msgpack))
# 输出: 66 36

在上面的例子中, MsgPack的体积比json的体积更小, 但是作为代价, MsgPack的可读性和JSON完全无法比较.

MsgPack包和JSON包在Python的用法几乎一致, 兼容性也很好, 在上面的用例中也将体积缩小了许多.

在性能上MsgPack据说也优于JSON, 此处不做深究.

Protocol Buffers

Protocol Buffers和MsgPack, Json都不同, 因为它需要预先定义.

在Python中, 你首先需要编写 .proto 文件, 然后使用谷歌提供的程序根据该文件生成可以被调用的python类.

Protocol Buffers同样支持许多语言(点我查看具体), 在本文只讨论Python+Protocol Buffers.

准备工作:

  1. protobuf包, 你可以使用 pip install protobuf 安装 [切记!]
  2. 用于生成类的protoc.exe, 你可以在他们在github上的项目中找到, (传送门)

首先编写好.proto文件:

syntax = "proto3";

message Response {
  string message = 1;
  int32 code = 2;
  optional string error = 3;
}

编写好以后, 用命令行执行刚刚下载好的protoc.exe(Linux/mac用户自行带入)

.\protoc.exe --python_out=<输出路径, 当前路径就写.> .\<.proto文件路径>  

注2: 谷歌文档给的不靠谱, 建议直接用这个

随后会在输出目录生成一个py文件, 在我们的测试用例中导入它:

import test_pb2

# {"message": "测试消息!", "code": 0, "error": None}
response = test_pb2.Response()

response.message = "测试消息!"
response.code = 0
data_protobuf = response.SerializeToString()  # 将数据转为二进制
 
print(data_protobuf) # b'\n\r\xe6\xb5\x8b\xe8\xaf\x95\xe6\xb6\x88\xe6\x81\xaf!'
print(len(data_protobuf)) # 15

response_read = test_pb2.Response()
response_read.ParseFromString(data_protobuf)
print(response_read)
# message: "测试消息!"

注意: Pycharm很可能会报错, 告诉你类不存在云云, 忽略即可.

可以看到Protobuf协议将空的error和为0的code忽略, 并将数据进一步压缩, 最终数据只有15的长度, 比MsgPack还要小一般有余.

ProtoBuf协议的效率比MsgPack更高, 不过其文档的坑点相当多, 下次单独开一个坑讲解一下官方文档完全没有提及的事情.

优劣分析

很显然Protocol Buffer的数据长度更短.

就语言本身的支持度而言, 毫无疑问JSON基本上啥语言都支持, MsgPack稍弱, Protocol Buffer则更少.

JSON/MsgPack在Python中都不需要预先定义任何协议格式, 可以很方便的从字典中直接转化. 但是Protocol Buffer需要, 所以灵活性相对弱一点.

JSON/MsgPack的类型绑定相当弱, 在一些强类型要求的语言中可能会出事(如: 超过int32边界值的数字), 需要预先考虑, Protocol Buffer在定义格式的过程中便预置了格式, 所以在开发过程中能够留意到这种问题:

# {"message": "测试消息!", "code": 2147483649, "error": None}
response.code = 2147483649
# ValueError: Value out of range: 2147483649
# python的 int 基本上可以视为无边界(相对于int64等)

Protocol Buffer对pycharm这类IDE支持较差, 自动补全肯定不用想, pycharm甚至会报错(打开生成的py文件, 你确实也看不到几个类, 疑似动态生成).

Protocol Buffer的文档可谓是相当陈旧, 在学习的时候, 谷歌官方的文档给出的, 生成python类的指令是存在问题的, 文档中也没有提及python需要具体安装的包. 在bing/百度上搜索到的中文文档多为对谷歌文档的直接翻译, 而文档似乎已经过时了, 所以需要自己多琢磨.

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
下一篇