还在用Protocol Buffers?快来看看FlatBuffers!

开发 前端
FlatBuffers 非常适合需要高性能数据传输的应用程序。它在速度、数据大小和类型安全性方面提供了显著优势,尽管学习曲线稍陡,但其性能提升和资源节省是值得的。

如果你正在寻找一种快速、高效的跨平台数据序列化库,FlatBuffers 绝对是一个值得探索的选择。由 Google 开发,FlatBuffers 旨在提供比其他序列化库(例如 Protocol Buffers 和 JSON)更高性能的解决方案。今天,我们将深入了解 FlatBuffers 的工作原理,通过一些代码示例展示如何使用它,并与其他常见的数据格式进行对比。

什么是 FlatBuffers?

FlatBuffers 是一个高效的、跨平台的序列化库,特别适用于游戏开发、网络通信和嵌入式系统。它具有以下几个主要特点:

  • 零拷贝反序列化:无需解析或解包即可直接访问数据。
  • 向后兼容:可以在不破坏现有数据格式的情况下扩展结构。
  • 多语言支持:支持多种编程语言,包括 C++, C#, C, Go, Java, JavaScript, PHP, Python, Rust, Swift 等。

安装 FlatBuffers

在开始之前,我们需要安装 FlatBuffers。以下是一些常见的安装方法:

使用 Homebrew(macOS)

brew install flatbuffers

使用 apt-get(Ubuntu)

sudo apt-get install flatbuffers-compiler

从源码编译

git clone https://github.com/google/flatbuffers.git
cd flatbuffers
cmake -G "Unix Makefiles"
make
sudo make install

快速入门示例

让我们通过一个简单示例来看看 FlatBuffers 是如何工作的。

定义模型

首先,我们需要定义一个数据模型。假设我们有一个包含人物信息的模型:

// person.fbs
namespace MyGame.Sample;

table Person {
id:int;
name:string;
age:int;
email:string;
}

root_type Person;

保存上述定义为 person.fbs 文件。

编译 FlatBuffers Schema

接下来,我们需要编译这个 schema 文件。这将生成用于我们应用程序的代码。

flatc --cpp person.fbs

使用 FlatBuffers 序列化和反序列化数据

现在我们已经生成了所需的代码,可以在 C++ 中使用它来序列化和反序列化数据。以下是一个简单的示例:

序列化

#include "person_generated.h"  // 自动生成的头文件
#include "flatbuffers/flatbuffers.h"
#include <iostream>

int main() {
 flatbuffers::FlatBufferBuilder builder;

 auto name = builder.CreateString("John Doe");
 auto email = builder.CreateString("john.doe@example.com");

 MyGame::Sample::PersonBuilder personBuilder(builder);
 personBuilder.add_id(123);
 personBuilder.add_name(name);
 personBuilder.add_age(30);
 personBuilder.add_email(email);

 auto person = personBuilder.Finish();

 builder.Finish(person);

 // 获取缓冲区指针和大小
 uint8_t* buf = builder.GetBufferPointer();
 int size = builder.GetSize();

 // 将缓冲区写入文件或发送
 std::cout << "Serialized data size: " << size << " bytes\n";

 return 0;
}

反序列化

#include "person_generated.h"
#include <iostream>

int main() {
 // 假设 buf 和 size 是从文件或网络读取的序列化数据
 uint8_t* buf = ...;
 int size = ...;

 auto person = MyGame::Sample::GetPerson(buf);

 std::cout << "ID: " << person->id() << "\n";
 std::cout << "Name: " << person->name()->str() << "\n";
 std::cout << "Age: " << person->age() << "\n";
 std::cout << "Email: " << person->email()->str() << "\n";

 return 0;
}

FlatBuffers 与其他数据格式的对比

让我们看看 FlatBuffers 和其他常见数据格式(如 JSON 和 Protocol Buffers)之间的主要差异。

FlatBuffers vs JSON

JSON 是一种文本格式,易于阅读和调试,广泛用于 web 应用程序。但它有几个缺点:

  • 性能:JSON 是文本格式,解析速度较慢。
  • 大小:JSON 数据通常比二进制格式大。
  • 类型安全:JSON 缺乏严格的类型约束。

FlatBuffers 的优势在于:

  • 速度:由于是二进制格式,解析和访问数据非常快。
  • 大小:二进制格式通常比 JSON 更小,占用更少的存储空间和网络带宽。
  • 类型安全:FlatBuffers 使用 schema 定义数据结构,提供了更强的类型安全性和数据验证。

FlatBuffers vs Protocol Buffers

Protocol Buffers(Protobuf)同样是由 Google 开发的序列化库,也使用二进制格式。它与 FlatBuffers 有相似之处,但也有一些关键区别:

  • 延迟:Protobuf 使用了“序列化-反序列化”的方式,这意味着数据在传输和存储时需要进行编码和解码。而 FlatBuffers 的零拷贝反序列化允许直接访问数据,减少了延迟。
  • 动态性:Protobuf 的 schema 更加灵活,可以更容易地进行字段的增加或删除。FlatBuffers 虽然也支持向后兼容,但在处理复杂的动态数据模型时可能不如 Protobuf 方便。
  • 生态系统:Protobuf 可能拥有更成熟和广泛的生态系统,特别是在 Google 内部的许多项目中都在使用。

性能对比

以下是一个简单的性能对比,可以帮助你更好地理解这些格式之间的差异:

特性

JSON

Protocol Buffers

FlatBuffers

解析速度

中等

数据大小

类型安全

序列化/反序列化

需要

需要

不需要(零拷贝)

可读性

向后兼容

较弱

较强

实践示例:FlatBuffers vs JSON

为了更直观地展示 FlatBuffers 的优势,我们来对比一下使用 FlatBuffers 和 JSON 序列化与反序列化的代码。

使用 JSON

序列化

#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main() {
  json person;
  person["id"] = 123;
  person["name"] = "John Doe";
  person["age"] = 30;
  person["email"] = "john.doe@example.com";

  std::string serialized_data = person.dump();
  std::cout << "Serialized JSON data: " << serialized_data << "\n";

  return 0;
}

反序列化

#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main() {
  std::string serialized_data = R"({"id":123,"name":"John Doe","age":30,"email":"john.doe@example.com"})";
  
  auto person = json::parse(serialized_data);
  std::cout << "ID: " << person["id"] << "\n";
  std::cout << "Name: " << person["name"] << "\n";
  std::cout << "Age: " << person["age"] << "\n";
  std::cout << "Email: " << person["email"] << "\n";

  return 0;
}

使用 FlatBuffers

上文已展示了如何在 C++ 中使用 FlatBuffers 进行序列化和反序列化。可以看到,虽然 JSON 的代码更为直观和易于调试,但 FlatBuffers 在性能和效率上具有显著优势,尤其是在处理大量数据或需要高频率数据交换的场景中。

结论

FlatBuffers 非常适合需要高性能数据传输的应用程序。它在速度、数据大小和类型安全性方面提供了显著优势,尽管学习曲线稍陡,但其性能提升和资源节省是值得的。

如果你的项目需要频繁的数据交换、高效的存储或需要在多种编程语言之间传递数据,FlatBuffers 是一个值得考虑的选择。希望这篇文章能帮助你更好地理解 FlatBuffers,并在你的项目中有效地应用它。

责任编辑:武晓燕 来源: 科学随想录
相关推荐

2022-11-28 07:32:46

迭代器remove数据库

2022-02-23 14:18:53

If-Else入参接口

2018-03-06 09:54:48

数据库备份恢复

2018-05-02 15:41:27

JavaScript人脸检测图像识别

2023-03-17 18:58:36

日志查询同步

2023-11-27 19:39:46

Goprotobuf

2020-04-16 09:35:53

数据科学机器学习数据分析

2018-04-18 17:08:45

2018-01-30 17:54:37

数据库MySQLSQL Server

2021-04-19 09:23:26

数字化

2018-03-12 10:35:01

LinuxBash快捷键

2022-05-05 09:14:41

AlpineDocker镜像开发

2022-05-12 15:17:09

GPU微软神经网络

2017-11-24 08:00:55

前端JSCSS

2020-08-04 07:02:00

TCPIP算法

2024-04-16 13:34:26

JSONMsgpack存储

2022-01-21 08:21:02

Web 安全前端程序员

2020-11-24 06:00:55

PythonPython之父编程语言

2020-08-19 10:34:26

编程语言开发

2020-06-08 15:06:33

Pandas可视化数据
点赞
收藏

51CTO技术栈公众号