【发布时间】:2011-07-21 09:59:53
【问题描述】:
在我从事的一个项目中,我必须通过网络来回发送浮点/双精度数组,我使用 Boost.Asio 来处理网络内容,因为我需要异步通信,而这只是似乎是最好的(唯一真正的?)那里......
发送的数组是浮点数/双精度数,类型双方都知道。 AFAIK,浮点存储标准可能存在问题 + 与 long/int、endians 等相同的问题。
从逻辑上讲,发送的数组是密集矩阵,一端由 Eigen 处理,另一端使用 BLAS / [MKL|ATLAS] 等等,很可能需要其他用途,所以我要最通用的方式,似乎是在数组周围传递。
关键要求是高性能和可移植性,因为客户端和服务器都可以在 32 / 64 位的任意组合上运行,并且通信非常密集(实时监控,每隔一秒刷新一次)客户端),因此序列化开销本身必须是最小的。
就我目前的发现而言,这里要考虑的两个大玩家是 Boost.Serialization 和 Google 的 Protobuf。
BS 的最大优点是我已经在项目中大量使用了 Boost(尽管单元测试在 Google 测试中),而且使用 make_array() 序列化数组似乎非常简单。它最大的缺点是性能。
我发现 protobuf 的优势在于性能,所有的实验似乎都表明它在任何操作上都比 BS 高出 10-20 倍。我在 protobuf 文档中没有找到的是在消息中添加一个数组。它使用重复的字段,据我了解,我必须在数组的每个元素上使用MsgObject.repeatedProp.Add(const T&),这意味着,对于一个 10k 数组,需要对其进行 10k 次调用,这似乎也有点昂贵。
任何关于如何解决这个问题的建议都将受到高度赞赏,因为我对 C++ 的经验是有限的,而且我最近才在较长时间休息后重新开始编写它......
【问题讨论】:
-
我无法评论用于添加项目的 C++ api(我在我的 C# 版本中避免了这种需要,但这对您没有帮助)- 只是说;如果您确实查看protobuf,这似乎是“打包数组”的一个很好的用例(它避免了每个元素的标头开销)。只是挤出一些额外性能的提示。
-
如果你真的需要超高性能,而且你所有的客户端都是x86/x64,你可以直接把二进制数据写出来。浮点数和双精度数分别占用 4 和 8 个字节,没有填充(unline long double),因此它们在两个平台上看起来都一样。它并不完全是“便携的”,但实际上它应该可以工作。
-
@Kerrek SB 我曾想过,但我记得在某处读到 reinterpret_cast 依赖于编译器实现,这真的会影响可移植性......
-
@TC1:如果你能抽出半个小时,何不试试看是否行得通?我很确定投射到
char*是 明确定义(正是为了这个目的),所以我相信你不会失望。无论如何都要向传输添加校验和:[size|**|**|...|**|checksum]. -
Kerrek 是绝对正确的。您可以将 float* 或 double* 重新解释为 char*。这使您可以访问底层字节,并允许您执行诸如字节交换之类的事情。 (我已经在从 MSVC 到用于移动设备的 ARM 编译器的各种平台上完成了它。)
标签: c++ serialization protocol-buffers boost-serialization