protobuf序列化/反序列化性能及问题

本文档详细记录了在Python 2.7环境下,使用protobuf进行序列化和反序列化的性能测试过程。测试结果显示,序列化和反序列化的时间随字节数线性增长,对于243MB的数据,分别耗时3s和4s。同时,与C++环境对比,Python的性能表现较差。作者提出测试方法的正确性和proto结构对性能的影响,建议在深入学习TensorFlow后进一步测试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为了tensorflow项目要求测试protobuf序列化/反序列化的性能,测试过程及测试结果如下:

一. 测试环境

python 2.7 + proto3

二. 测试方法

1. 自定义一个proto消息(使用protobuf example里的例子,进行修改

message Person {
  string name = 1;
  int32 id = 2;  // Unique ID number for this person.
  string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;
}

// Our address book file is just one of these.
message AddressBook {
  repeated Person people = 1;
}


2. 编译proto文件

protoc --python_out=. address.proto

得到 addressbook_pb2.py


3. 在测试文件中,通过修改循环的大小,修改序列化内容的大小。并

for i in range(1024 * 1024):
  PromptForAddress(address_book.people.add())

4. 序列化

  begin = datetime.datetime.now()
  serialized = address_book.SerializeToString()
  end = datetime.datetime.now()
  print end-begin
  print len(serialized)
  f.write(serialized)

5. 反序列化

    book = f.read()
    parsebegin = datetime.datetime.now()
    address_book.ParseFromString(book)
    parseend = datetime.datetime.now()
    print parseend-parsebegin
    print len(book)

完整的py文件如下:

#! /usr/bin/env python

# See README.txt for information and build instructions.

import addressbook_pb2
import sys
import datetime

# This function fills in a Person message based on user input.
def PromptForAddress(person):
  person.id = 160824
  person.name = "xxxxx xxxxx"
  person.email = "xxxxxxxx@xxxxx.com"
  phone_number = person.phones.add()
  phone_number.number = "12345678"
  phone_number.type = addressbook_pb2.Person.MOBILE

  phone_number = person.phones.add()
  phone_number.number = "23456789"
  phone_number.type = addressbook_pb2.Person.HOME

  phone_number = person.phones.add()
  phone_number.number = "34567890"
  phone_number.type = addressbook_pb2.Person.WORK

# Main procedure:  Reads the entire address book from a file,
#   adds one person based on user input, then writes it back out to the same
#   file.
if len(sys.argv) != 2:
  print "Usage:", sys.argv[0], "ADDRESS_BOOK_FILE"
  sys.exit(-1)
address_book = addressbook_pb2.AddressBook()

# Read the existing address book.
try:
  with open(sys.argv[1], "rb") as f:
    book = f.read()
    parsebegin = datetime.datetime.now()
    address_book.ParseFromString(book)
    parseend = datetime.datetime.now()
    print parseend-parsebegin
    print len(book)



#    address_book.ParseFromString(f.read())
except IOError:
  print sys.argv[1] + ": File not found.  Creating a new file."

# Add an address.
for i in range(1024 * 1024):
  PromptForAddress(address_book.people.add())

# Write the new address book back to disk.
with open(sys.argv[1], "wb") as f:
  begin = datetime.datetime.now()
  serialized = address_book.SerializeToString()
  end = datetime.datetime.now()
  print end-begin
  print len(serialized)
  
'''
address_book = addressbook_pb2.AddressBook()

# Read the existing address book.
try:
  with open(sys.argv[1], "rb") as f:
    book = f.read()
    parsebegin = datetime.datetime.now()
    address_book.ParseFromString(book)
    parseend = datetime.datetime.now()
    print parseend-parsebegin
    print len(book)
'''

6. 修改循环次数,记录不同大小的protobuf序列化反序列的性能

三. 测试结果

 

字节(MB)

序列化(s)

反序列化(s)

1.03

0.799453

0.950107

53.00

36.759911

43.303041

61.64

41.674104

52.206466

81.00

63.077295

79.234909

106.00

72.048027

88.280556

102.83

81.08806

102.28786

162.00

128.883403

164.042591

205.66

163.994605

199.729636

243.00

197.582673

246.699898


注:表中字节大小为序列化后得到的字符串大小,即程序中的 
len(serialized) 


四. 测试分析及问题

根据测试的结果看是基本成线性增长,字节数越大,所用时间越多。当字节数为243MB时,序列化耗时3s左右,反序列化耗时4s左右。在测试结果上有几个问题如下:

1. 测试方法是否正确,我感觉应该是可行的,但是结果比我预期的要大。

2. 本次测试是用Python测试的,我在c++下进行测试,得到的结果比python好很多(C++部分参考FlatBuffers与protobuf性能比较

我只对比测试了小数据量(1KB)的,序列化及反序列化均循环100次,结果如下:(两次测试的proto文件为同一个,在C++中用的序列化/反序列化函数为ParseFromArray/SerializeToArray,python中用的序列化/反序列化函数是ParseFromString/SerializeToString)

 

序列化(毫秒)

反序列化(毫秒)

Python

63.879

82.89

C++

1.336

1.352


测试结果显示c++的性能比Python快60-80倍,c++是否能比Python快这么多?

3. 经查阅相关资料,序列化反序列化跟proto的结构也是有关系的(比如多层嵌套),所以建议在学习tensorflow之后结合tensorflow再进行一次测试,在训练某一个模型时,将其中序列化反序列化的过程单独计时。


以上两个问题还需讨论,也欢迎各位批评指正。


五. 参考及学习文章

1. FlatBuffers与protobuf性能比较

2. (pbc lua 加入)c++_lua_Python with/without extension性能测试 (10万次SerializeToString & ParseFromString)

3. 使用Protocol Buffers的C语言拓展提速Python程序的示例

4. protobuf中会严重影响时间和空间损耗的地方 

5. Protobuf使用不当导致的程序内存上涨问题

6. protobuffer性能分析测试

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值