FlatBuffers Python 使用指南:库结构、读写与 NumPy 向量加速
【免费下载链接】flatbuffersFlatBuffers: Memory Efficient Serialization Library项目地址: https://gitcode.com/GitHub_Trending/fl/flatbuffers
本篇指南基于 FlatBuffers 官方文档中 Python 语言章节,系统讲解如何在 Python 中读写 FlatBuffers 二进制数据:包括 Python 运行库在仓库中的位置、flatc --python代码生成与项目集成方式、GetRootAsMonster读取流程、AsNumpy()向量零拷贝加速,以及文本解析的能力边界。读完本文,你将能够独立完成"编写 schema → 生成 Python 代码 → 序列化/反序列化 → 用 NumPy 批量读取标量向量"的完整链路。
开始之前:需要掌握的前置知识
本文是 Tutorial 的 Python 语言专项补充,聚焦 Python 使用上的细节与差异。建议在阅读本文前先完成以下准备工作:
- 通读 Tutorial:其中包含全部支持语言(含 Python)的完整使用指南,覆盖 schema 编写、
flatc编译、应用集成、序列化与反序列化全流程; - 阅读 Building 文档并构建出
flatc编译器; - 熟悉 Using the schema compiler 与 Writing a schema,掌握
flatc的命令行用法与.fbsschema 语法。
# 在仓库根目录下用 CMake 构建 flatc(Unix 环境) cmake -G "Unix Makefiles" make flatc构建完成后,flatc可执行文件位于仓库根目录(tests/PythonTest.sh正是以../flatc方式引用它)。
FlatBuffers Python 库代码位置
Python 运行时库的源码位于仓库的python/flatbuffers目录,由以下核心模块组成:
| 模块文件 | 职责 |
|---|---|
| python/flatbuffers/builder.py | Builder类,序列化核心,管理字节缓冲与 vtable |
| python/flatbuffers/table.py | Table类,只读访问器基类,提供向量/字符串/联合的读取 |
| python/flatbuffers/encode.py | 标量编解码与GetVectorAsNumpy实现 |
| python/flatbuffers/number_types.py | 各标量类型的 packer 与 NumPy dtype 映射 |
| python/flatbuffers/packer.py | 基于struct的小端二进制打包 |
| python/flatbuffers/compat.py | Python 2/3 兼容层与 NumPy 可选依赖探测 |
| python/flatbuffers/flexbuffers.py | FlexBuffers 变长格式支持 |
| python/flatbuffers/util.py | 工具函数(如GetBufferIdentifier) |
该目录还提供标准的打包配置:python/setup.py(当前版本号25.12.19)与 python/setup.cfg,可通过pip install flatbuffers安装,或直接将python目录加入PYTHONPATH使用仓库内源码。
测试 Python 库
Python 库的测试代码位于 tests/py_test.py,覆盖了对象 API、向量、联合、gRPC、NumPy 向量等大量场景。运行测试使用 tests/PythonTest.sh 脚本:
# 需已安装 Python;脚本会自动探测可用的解释器 cd tests ./PythonTest.sh该脚本会依次完成以下工作(详见 tests/PythonTest.sh):
- 用仓库内
flatc针对monster_test.fbs、monster_extra.fbs、arrays_test.fbs、nested_union_test.fbs、service_test.fbs等 schema 生成 Python 代码,生成命令带有--gen-object-api、--python-typing、--gen-compare、--gen-onefile、--grpc、--grpc-python-typed-handlers、--no-python-gen-numpy、--python-decode-obj-api-strings等选项; - 依次用
python2.6、python2.7、python3、pypy运行 tests/py_test.py(若环境中存在),并对python3额外运行 tests/py_flexbuffers_test.py; - 若安装了
coverage(pip install coverage),还会以默认 Python 生成覆盖率报告; - 若系统没有任何 Python 解释器,则输出 "No Python interpreters found" 并退出码 1。
运行方式示例:python3 py_test.py 100 100 100 100 false(后四个参数是 vtable 去重、读/写基准测试的次数与开关)。
在 Python 中使用 FlatBuffers
Python 同时支持 FlatBuffers 的读取与写入。整体流程是:先用flatc的--python选项从 schema 生成 Python 类,然后在业务代码中同时导入 FlatBuffers 运行时库与生成的代码。
第一步:用 flatc 生成 Python 代码
flatc --python monster.fbs生成的文件会按 schema 中的namespace组织成对应的 Python 包(例如MyGame/Example目录下的Monster.py、Vec3.py等)。以本仓库 samples/monster.fbs 为例,其namespace MyGame.Sample;会生成MyGame/Sample/包。也可以像测试脚本那样追加--gen-object-api(生成可变的 Object API 与Pack/UnPack方法)、--python-typing(生成.pyi类型标注文件)等选项。
第二步:读取一个 FlatBuffer 二进制文件
import MyGame.Example as example # flatc --python 生成的代码 import flatbuffers # 运行时库 # 将二进制文件读入 bytearray buf = open('monster.dat', 'rb').read() buf = bytearray(buf) # 以根对象方式解析 monster = example.GetRootAsMonster(buf, 0)随后即可像普通访问器一样读取字段:
hp = monster.Hp() pos = monster.Pos()这里的GetRootAsMonster(buf, 0)是flatc生成代码提供的入口函数:buf是bytearray形式的二进制数据,0是根对象在缓冲中的偏移。读取器底层由 python/flatbuffers/table.py 中的Table类支撑——它保存Bytes与Pos两个状态,通过Offset()查询 vtable、Get()解码标量、String()/Vector()解析引用类型,并利用GetSlot()在字段缺失时返回 schema 中声明的默认值,因此读取过程不产生反序列化副本、无需解析整棵树,这正是 FlatBuffers 零拷贝读取特性的体现。
写入(序列化)示例
如果需要写入,则使用 python/flatbuffers/builder.py 中的Builder:
import flatbuffers import MyGame.Sample.Monster import MyGame.Sample.Vec3 import MyGame.Sample.Color import MyGame.Sample.Equipment # 构造 Builder,默认初始缓冲 1024 字节,需要时会自动扩容 builder = flatbuffers.Builder(1024) # 引用类型(string、vector、table)需先序列化,自叶子向根构建 name = builder.CreateString("Orc") inv = builder.CreateStringVector([0, 1, 2, 3]) # 或用 CreateNumpyVector MyGame.Sample.Monster.Start(builder) MyGame.Sample.Monster.AddPos(builder, MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0)) MyGame.Sample.Monster.AddHp(builder, 300) MyGame.Sample.Monster.AddName(builder, name) MyGame.Sample.Monster.AddInventory(builder, inv) MyGame.Sample.Monster.AddColor(builder, MyGame.Sample.Color.Color().Red) orc = MyGame.Sample.Monster.End(builder) builder.Finish(orc) # 标记根对象 buf = builder.Output() # 必须在 Finish() 之后调用,返回 bytearray从源码实现看,Builder的几个关键行为值得注意(见 python/flatbuffers/builder.py):
- 向后构建:缓冲从尾部向前写入,
head指向当前写入位置,读取时无需前向解析; - 初始大小与上限:
Builder(initialSize=1024),缓冲可自动增长,但受MAX_BUFFER_SIZE = 2**31(2 GiB)硬上限约束,超过会抛出BuilderSizeError; - vtable 去重:
WriteVtable()会将新 vtable 与已记录的self.vtables比较,内容相同的对象复用已有 vtable,从而显著压缩重复结构的内存占用; Output()前必须Finish():否则抛出BuilderNotFinishedError;Output()返回的是Bytes[head:]切片,即实际已写入的数据;- 序列化过程的状态机还会抛出
IsNotNestedError、IsNestedError、StructIsNotInlineError、EndVectorLengthMismatched等异常,用于在嵌套/顺序错误时给出明确提示。
对 NumPy 数组的支持
Python 库对标量向量提供 NumPy 数组访问支持。相比逐元素迭代,这可以带来数量级的性能提升,尤其在解包大型嵌套 FlatBuffers 时优势明显。生成的代码会为每个标量向量提供一个<vector name>AsNumpy()方法。以 Monster 示例的inventory向量为例:
inventory = monster.InventoryAsNumpy() # inventory 是一个 numpy 数组,类型为 np.dtype('uint8')而不是:
inventory = [] for i in range(monster.InventoryLength()): inventory.append(int(monster.Inventory(i)))从实现看,AsNumpy()的底层链路是:生成的访问器调用Table.GetVectorAsNumpy()(见 python/flatbuffers/table.py),先定位向量起始位置与长度,再按字段类型映射到 NumPy dtype(映射表在 python/flatbuffers/number_types.py 的to_numpy_type),最终在 python/flatbuffers/encode.py 中通过np.frombuffer(buf, dtype=numpy_type, count=count, offset=offset)构造数组。也就是说,返回的 NumPy 数组是原缓冲区的零拷贝视图(view)——修改该数组会直接改动底层Bytes,同时避免了逐元素 Python 循环的开销。
NumPy 不是必需依赖
NumPy 是可选依赖。运行库在 python/flatbuffers/compat.py 的import_numpy()中通过探测模块是否存在来决定是否导入:存在则正常加载,不存在则置为None。
- 若系统未安装NumPy,调用任何
*AsNumpy()方法都会抛出NumpyRequiredForThisFeature异常(该异常继承自RuntimeError,定义于 python/flatbuffers/compat.py); - 因此,只有当你确实需要 NumPy 向量访问时,才需要额外安装
pip install numpy; - 官方测试 tests/py_test.py 对此做了双向验证:当 NumPy 存在时,断言
InventoryAsNumpy().dtype == np.dtype('<u1')且sum() == 10;当 NumPy 不存在时,则断言访问AsNumpy()会抛出NumpyRequiredForThisFeature。
该特性同时覆盖多种标量类型与固定长度数组:测试中还包含TestarrayofboolsAsNumpy、VectorOfLongsAsNumpy、VectorOfDoublesAsNumpy、VectorOfEnumsAsNumpy以及test_create_numpy_vector_*系列用例(对应CreateNumpyVector写入 API),说明布尔、长整型、浮点、枚举向量乃至arrays_test的定长数组都可享受同样的零拷贝批量访问能力。
文本解析(JSON/Schema)说明
目前 Python 库不支持直接从 Python 解析文本格式(包括.fbsschema 与 JSON 数据)。如果需要文本解析能力,官方文档给出的路径是:
- 通过 SWIG 或 ctypes 包装并调用 C++ 解析器;
- 或者直接查阅 C++ 文档(
docs/source/languages/cpp.md)了解文本解析的完整实现。
这也意味着 Python 侧的常规使用方式是:schema 文本交由flatc编译为二进制flatc文件或直接生成代码,JSON 与二进制之间的转换可借助flatc -t --json等命令完成,而运行时只处理二进制格式。
小结
- 库位置:运行时库在 python/flatbuffers,可通过
pip install flatbuffers安装或以PYTHONPATH引用仓库源码; - 读写流程:
flatc --python monster.fbs生成代码 → 导入flatbuffers与生成包 → 读取用GetRootAsMonster(buf, 0),写入用Builder+Start/Add/End+Finish()+Output(); - 性能关键点:标量向量用
<name>AsNumpy()获得零拷贝 NumPy 视图,避免逐元素迭代;NumPy 为可选依赖,缺失时访问会抛NumpyRequiredForThisFeature; - 能力边界:文本(schema/JSON)解析需借助 C++ 解析器(SWIG/ctypes),Python 库本身不提供。
如需完整的逐语言对照示例与 schema 类型系统讲解,请继续阅读 Tutorial、Writing a schema 与 Using the schema compiler。
【免费下载链接】flatbuffersFlatBuffers: Memory Efficient Serialization Library项目地址: https://gitcode.com/GitHub_Trending/fl/flatbuffers
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考