如何以正确的方式在 python 中使用平面缓冲区?

How to use flatbuffers in python the right way?

我有两个关于在 python 中使用平面缓冲区的问题,重点是如何以正确的方式使用它们而不编写完全破坏其性能优势的代码。我想在 C# 和 python 程序之间使用平面缓冲区进行序列化和网络通信。我已经阅读了 tutorial, python specifics 和一些将其他语言与平面缓冲区一起使用的博文,但找不到 python.

1.) Flatbuffers 用于快速序列化。 python 也是如此吗? python 的 performance 只是声明 "Ok" 而其他语言得到 "Great"。具体时间不详。我知道 python 通常不如 C 或 C++ 快,但我们说的有多慢?到它破坏其承诺的性能优势的地步(例如与 JSON 相比)?也许有人已经用 python 做过基准测试?如果没有,我将尝试编写一个比较 C# 和 python 之间的时间以及 python.

中的 flattbuffers 与 json 的时间

2.) 它很快,因为 "zero copy"。但这对于需要更改数据的程序意味着什么?特别是因为对象是不可变的。为了与它们一起工作,无论如何我都需要将值复制到对象的本地表示中。这不是破坏了目的吗?本教程说明了这个从平面缓冲区读取的示例:

import MyGame.Example as example
import flatbuffers
buf = open('monster.dat', 'rb').read()
buf = bytearray(buf)
monster = example.GetRootAsMonster(buf, 0)
hp = monster.Hp()
pos = monster.Pos()

最后两行不就是抄袭吗?

  1. 您没有提到任何具体的 link。我猜 flatbuffers 的性能将取决于调用 API 时来自 Python 的序列化。众所周知,Python 比 C 或 C++ 慢。

  2. 关于zero-copy - Google(和Wikipedia)是你的朋友。

  3. 教程说 "depending on language"。你所说的表明在 Python 中你不会得到例外。

  4. 文档怎么说?你的实验证实了吗? (向我们展示解决问题的一些努力)

  5. 不好说。你尝试了什么,得到了什么结果?

FlatBuffers 的设计非常有利于像 C/C++/Rust 这样的语言来获得最大速度。 Python 实现模仿了这些语言的作用,但它对于 Python 来说非常不自然,因此如果您纯粹为 Python 设计,它并不是最快的序列化程序设计。

我没有在 Python 上进行任何基准测试,但 Python 特定设计在许多情况下肯定会击败 FlatBuffers-Python。 FlatBuffers 设计甚至在 Python 中获胜的一种情况是对于稀疏或随机访问的大文件,因为它实际上并没有一次解压所有数据。

您通常使用 FlatBuffers,因为您的堆栈中的性能关键部分使用更快的语言,然后您还希望能够在其他地方处理 Python 中的数据。但是,如果您纯粹在 Python 中工作,FlatBuffers 可能不是您的最佳选择(除非您再次处理大量稀疏数据)。

当然最好不要在 Python 中做繁重的工作。

我现在在 python 中做了一个基准来比较 JSON 和 flatbuffers 并且认为答案可能对某些人有用,所以我们开始:

设置如下:我们有一个客户端服务器架构(在同一台机器上),都在 python 中,带有套接字和异步。测试数据是一个大字典,其值为字符串、数字和列表,其中包含其他字典也具有字​​符串、数字和列表值。这棵树最多有 3 层深,每个列表大约有 100 个对象。

flatbuffer 模式对字典使用表,对列表使用向量,对仅使用 float 和 int 字段的字典使用结构。

flatbuffer测试的测试数据为:

  • 填充到平面缓冲区构建器中并作为字节数组返回(序列化)
  • 通过套接字和异步发送到服务器reader/writer
  • 从 bytearray 转换回 fb-object 并且一些字段被服务器访问(反序列化)
  • 然后 deserialization-time 被发送回客户端。

JSON测试的测试数据为:

  • 通过 dumps() 转换为字符串,然后转换为字节数组
  • 通过套接字和异步发送到服务器reader/writer
  • 从 bytearray 转换为字符串,然后通过 json.loads() 转换回字典;比服务器访问相同的几个字段(反序列化)
  • 然后 deserialization-time 被发送回客户端。

我知道,关于设置,有一些观点可以争论。例如,在 flatbuffer 测试中不将数据转换回字典。如果有人真的对此感兴趣,我可以提前进行此测试。

但是现在来看看结果:

--- flatbuffers  ---
roundtrip time:   7.010654926300049
serialize time:   6.960820913314819
deserialize time: 0.0
size in byte:     6.365.432
---     json     ---
roundtrip time:   0.7860651016235352
serialize time:   0.3211710453033447
deserialize time: 0.28783655166625977
size in byte:     13.946.172

我的结论是,如果您想快速编辑或创建数据,则不应在 python 中使用平面缓冲区。无法改变 python 中的数据,这意味着每次发生变化时都必须重建平面缓冲区,这非常慢。

好的一面是,与 JSON 相比,读取数据的速度非常快,字节大小非常小。因此,如果您有要多次发送或读取的静态数据,平面缓冲区将是解决方案。