性能flatbuffer vs protobuf

时间:2018-10-29 11:00:11

标签: protocol-buffers flatbuffers

有人告诉我,flatbuffer的性能比proto好,我对flatbuffer和protobuf的性能进行了测试,我可以确定std向量没有影响。通过序列化和脱序列可以很快,但是总花费时间是不止是原始的。 protobuf比flatbuf更好,还是我在某些细节上犯了错误?

flatbuffer样本

    #include"person.pb.h"
#include<sys/time.h>
int main(int argc,char *argv[])
{
  if(argc<2)
  {
    printf("<usage> num\n");
    return -1; 
  }
  size_t iNum = strtoul(argv[1],NULL,10);

  person::School school;
  for(size_t i=0;i<iNum;++i)
  {
     person::Person *p = school.add_student();
     p->set_name("rockycai");
     p->set_age(i);  
  }

  timeval tbegin,tend;

  std::string buffer;

  gettimeofday(&tbegin,NULL);
  school.SerializeToString(&buffer);
  gettimeofday(&tend,NULL);

  unsigned long int uUsedMs = (tend.tv_sec - tbegin.tv_sec) * 1000 +
                                (tend.tv_usec - tbegin.tv_usec) / 1000;

  printf("serialize size %u cost time %lu\n",buffer.size(),uUsedMs);

  person::School school1;

  gettimeofday(&tbegin,NULL);
  school1.ParseFromString(buffer);
  gettimeofday(&tend,NULL);

  uUsedMs = (tend.tv_sec - tbegin.tv_sec) * 1000 +
                                (tend.tv_usec - tbegin.tv_usec) / 1000;

  printf("deserialize time %lu\n",uUsedMs); 

  return 0;
}

protbuf示例:

timeval tbegin,tend;
  gettimeofday(&tbegin,NULL);

  timeval tbegin1,tend1;
  unsigned long int iTotal = 0;
  for(size_t i=0;i<iNum;++i)
  {
     auto name = builder.CreateString("rockycai"); 
     uint32_t age = i;

     auto student = CreateStudent(builder,name,age);

     gettimeofday(&tbegin1,NULL);
     student_vector.push_back(student);
     gettimeofday(&tend1,NULL);

     iTotal += ((tend1.tv_sec - tbegin1.tv_sec) * 1000 + (tend1.tv_usec - tbegin1.tv_usec) / 1000);
  }
  gettimeofday(&tend,NULL);

  unsigned long int uUsedMs = (tend.tv_sec - tbegin.tv_sec) * 1000 +
                                (tend.tv_usec - tbegin.tv_usec) / 1000;

  printf("insert time %lu vector time %lu\n",uUsedMs,iTotal);

  gettimeofday(&tbegin,NULL);
  auto vecStu = builder.CreateVector(student_vector);
  auto school = CreateSchool(builder,vecStu);
  gettimeofday(&tend,NULL);

  uUsedMs = (tend.tv_sec - tbegin.tv_sec) * 1000 + (tend.tv_usec - tbegin.tv_usec) / 1000;
  printf("flat prepare time %lu\n",uUsedMs);

  gettimeofday(&tbegin,NULL);
  builder.Finish(school);
  gettimeofday(&tend,NULL);

  uUsedMs = (tend.tv_sec - tbegin.tv_sec) * 1000 +
                                (tend.tv_usec - tbegin.tv_usec) / 1000;

  printf("serialized size %u costtime %lu\n",builder.GetSize(),uUsedMs);


  gettimeofday(&tbegin,NULL);
  auto res = GetSchool(builder.GetBufferPointer());
  gettimeofday(&tend,NULL);

  uUsedMs = (tend.tv_sec - tbegin.tv_sec) * 1000 + (tend.tv_usec - tbegin.tv_usec) / 1000;
  printf("deserialize time %lu\n",uUsedMs);

flatbuffer结果

 $ ./sample_person 10000000
insert time 9232 vector time 1
flat prepare time 1493
serialized size 320000024 costtime 0
deserialize time 0

protobuf结果

$ ./test_person 10000000                                                                            
serialize size 167886336 cost time 2799
deserialize time 4446

平面定义

  namespace My.School;

table Student
{
  name:string;
  age:uint32;
}

table School
{
  student:[Student];
}
root_type School;

原型定义

package person;

message Person
{
  optional string name = 1;
  optional uint32 age = 2;
}

message School
{
  repeated Person student = 1;
}

更新...整个代码:

#include "person_generated.h"
#include<sys/time.h>
using namespace My::School;

int main(int argc,char *argv[])
{
  timeval ttbegin,ttend;
  gettimeofday(&ttbegin,NULL);

  if(argc<2)
  {
     printf("<usage> num\n");
     return -1;
  }

  size_t iNum = strtoul(argv[1],NULL,10);
  flatbuffers::FlatBufferBuilder builder(10000000);
  std::vector<flatbuffers::Offset<Student>> student_vector;
  student_vector.reserve(10000000);

  timeval tbegin,tend;
  gettimeofday(&tbegin,NULL);

  //timeval tbegin1,tend1;
  unsigned long int iTotal = 0;
  for(size_t i=0;i<iNum;++i)
  {
     auto name = builder.CreateString("rockycai");
     uint32_t age = i;

     auto student = CreateStudent(builder,name,age);

     //gettimeofday(&tbegin1,NULL);
     student_vector.push_back(student);
     //gettimeofday(&tend1,NULL);

     //iTotal += ((tend1.tv_sec - tbegin1.tv_sec) * 1000 + (tend1.tv_usec - tbegin1.tv_usec) / 1000);
  }

  gettimeofday(&tend,NULL);

  unsigned long int uUsedMs = (tend.tv_sec - tbegin.tv_sec) * 1000 +
                                (tend.tv_usec - tbegin.tv_usec) / 1000;

  printf("insert time %lu\n",uUsedMs);

  gettimeofday(&tbegin,NULL);

  auto vecStu = builder.CreateVector(student_vector);
  auto school = CreateSchool(builder,vecStu);

  gettimeofday(&tend,NULL);
    uUsedMs = (tend.tv_sec - tbegin.tv_sec) * 1000 + (tend.tv_usec - tbegin.tv_usec) / 1000;
  printf("flat prepare time %lu\n",uUsedMs);

  gettimeofday(&tbegin,NULL);
  builder.Finish(school);

  gettimeofday(&tend,NULL);

  uUsedMs = (tend.tv_sec - tbegin.tv_sec) * 1000 +
                                (tend.tv_usec - tbegin.tv_usec) / 1000;

  printf("serialized size %u costtime %lu\n",builder.GetSize(),uUsedMs);


  gettimeofday(&tbegin,NULL);
  auto res = GetSchool(builder.GetBufferPointer());

  gettimeofday(&tend,NULL);

  uUsedMs = (tend.tv_sec - tbegin.tv_sec) * 1000 + (tend.tv_usec - tbegin.tv_usec) / 1000;
  printf("deserialize time %lu\n",uUsedMs);

  gettimeofday(&ttend,NULL);

  uUsedMs = (ttend.tv_sec - ttbegin.tv_sec) * 1000 + (ttend.tv_usec - ttbegin.tv_usec) / 1000;
  printf("total time %lu\n",uUsedMs);
  return 0;
}




 #include"person.pb.h"
#include<sys/time.h>
int main(int argc,char *argv[])
{

  timeval ttbegin,ttend;
  gettimeofday(&ttbegin,NULL);

  if(argc<2)
  {
    printf("<usage> num\n");
    return -1; 
  }
  size_t iNum = strtoul(argv[1],NULL,10);

  person::School school;

  timeval tbegin,tend;
  gettimeofday(&tbegin,NULL);
  for(size_t i=0;i<iNum;++i)
  {
     person::Person *p = school.add_student();
     p->set_name("rockycai");
     p->set_age(i);  
  }

  gettimeofday(&tend,NULL);  

  unsigned long int uUsedMs = (tend.tv_sec - tbegin.tv_sec) * 1000 + (tend.tv_usec - tbegin.tv_usec) / 1000;

  printf("vector time %lu\n",uUsedMs);
  std::string buffer;

  gettimeofday(&tbegin,NULL);
  school.SerializeToString(&buffer);
  gettimeofday(&tend,NULL);

  uUsedMs = (tend.tv_sec - tbegin.tv_sec) * 1000 +
                                (tend.tv_usec - tbegin.tv_usec) / 1000;

  printf("serialize size %u cost time %lu\n",buffer.size(),uUsedMs);

  person::School school1;

  gettimeofday(&tbegin,NULL);
  school1.ParseFromString(buffer);
  gettimeofday(&tend,NULL);

  uUsedMs = (tend.tv_sec - tbegin.tv_sec) * 1000 +
                                (tend.tv_usec - tbegin.tv_usec) / 1000;

  printf("deserialize time %lu\n",uUsedMs); 

    gettimeofday(&ttend,NULL);
  uUsedMs = (ttend.tv_sec - ttbegin.tv_sec) * 1000 + (ttend.tv_usec - ttbegin.tv_usec) / 1000;
  printf("total time %lu\n",uUsedMs);

  return 0;
}

res is:



 $ ./sample_person 10000000
insert time 7763
flat prepare time 1159
serialized size 320000024 costtime 0
deserialize time 0
total time 8922




  $ ./test_person 10000000
vector time 2598
serialize size 167886336 cost time 2706
deserialize time 4676
total time 9981

1 个答案:

答案 0 :(得分:1)

您可能希望将gettimeofday从内部循环中删除,因为这可能会花费大量时间来影响计时。如果您不希望push_back花费任何费用,请确保在循环之前保留其大小。

对于其余的代码,比较是苹果与橘子。对于ProtoBuf,您仅测量SerializeToString,而要使此功能正常工作,您必须分配(并取消分配)Protobuf对象的向量。您这次没有测量。 FlatBuffer一次性完成了所有这些工作,成为序列化的一部分,它不需要中间的数据结构(除了上面提到的向量)。

代码也没有显示如何创建FlatBufferBuilder,因为默认大小合适会带来很大的不同。

相关问题