C ++便携式阵列序列化

时间:2011-07-21 09:59:54

标签: c++ serialization protocol-buffers boost-serialization

在我工作的项目中,我必须通过网络来回发送浮点数/双数组,我使用Boost.Asio作为网络内容,因为我需要通信是异步的,并且那里似乎是最好的(唯一真实的?)...

发送的数组是浮点数/双精度数,并且双方都知道该类型。 AFAIK,浮点存储标准可能存在问题+与longs / int,endians等相同的东西。

逻辑上,发送的数组是密集矩阵,由Eigen在一端处理,使用BLAS / [MKL | ATLAS]而在另一端,很可能需要其他用途,所以我要去以最通用的方式&这似乎是在数组周围传播。

关键要求是高性能和可移植性,因为客户端和服务器都可以在32/64位的任意组合上运行,并且通信非常紧张(实时监控,每秒刷新一次)客户端),因此序列化开销本身必须是最小的。

据我所知,到目前为止,这里要考虑的两个主要参与者是Boost.Serialization和Google的Protobuf。

BS的最大优点是我在项目中已经使用了很多Boost(尽管单元测试是在Google Test中),并且使用make_array()序列化数组似乎非常简单。最重要的是表现。

从我发现的protobuf的优势是性能,所有的长凳似乎表明它在任何操作上都优于BS 10-20倍。我在protobuf文档中找不到的是在消息中添加一个数组。它使用重复的字段,根据我的理解,我必须在数组的每个元素上使用MsgObject.repeatedProp.Add(const T&),这意味着,即10k数组的10k调用,这看起来很有用也很昂贵。

关于如何解决这个问题的任何建议都会受到高度赞赏,因为我对C ++的经验有限,而且我最近才重新开始在长时间休息后写作...

3 个答案:

答案 0 :(得分:1)

除了升级asio之外,您可能还想看看boost.MPI(消息传递接口)。这使用boost.serialization进行幕后序列化。

Boost.mpi discusses booost.serialization可能的性能优化。特别是使用

  • BOOST_CLASS_TRACKING(gps_position类型,track_never)
  • BOOST_CLASS_IMPLEMENTATION(gps_position,object_serializable)

宏和mpi定义的宏

  • BOOST_IS_MPI_DATATYPE(gps_position)

这些优化似乎运作良好,请参阅this图。

我从未使用过protobuff,所以我不能说这个。

答案 1 :(得分:1)

使用protobufs,如果使用“bytes”而不是“repeat int32”(或类似)对数组进行编码,则可以使10k数组的10k调用无效。 在你的代码中,如果你转换指针并使用memcpy,它通常会非常快。

答案 2 :(得分:0)

在github上有很好的例子。以下是进出协议缓冲区eigen和矩阵的一些可能资源:

  • HAL硬件抽象库(机器人技术)。
  • Tensorflow对张量(nd数组)做了很多相同的事情,但考虑到它们支持的扩展功能集,它们的实现可能要复杂得多。
  • NUbots有另一个例子。
  • Chromium似乎也有例子。
  • ceres-solver曾用于支持protobufs for matrices但此功能已被删除。 (header

这是HAL版本,它很简单,看起来效果很好:

Protobuf for storing a matrix

package hal;

message MatrixMsg {
  required uint32 rows = 1;
  // columns deduced by division. Data stored as column major
  repeated double data = 2 [packed=true];
}

message VectorMsg {
  repeated double data = 1 [packed=true];
}

Loading into eigen and writing to protobuf

#pragma once

#include <Eigen/Eigen>
#include <HAL/Messages.pb.h>

namespace hal {

inline void ReadMatrix(const MatrixMsg &msg, Eigen::MatrixXd* mat) {
  mat->resize(msg.rows(),msg.data_size()/msg.rows());
  for(int ii = 0 ; ii < msg.data_size() ; ii++){
    mat->operator()(ii) = msg.data(ii);
  }
}

inline void ReadVector(const VectorMsg &msg, Eigen::VectorXd* vec) {
  vec->resize(msg.data_size());
  for(int ii = 0 ; ii < msg.data_size() ; ii++){
    vec->operator()(ii) = msg.data(ii);
  }
}

inline void WriteMatrix(const Eigen::MatrixXd &mat, MatrixMsg *msg) {
  msg->set_rows(mat.rows());
  msg->mutable_data()->Reserve(mat.rows()*mat.cols());
  for(int ii = 0 ; ii < mat.cols()*mat.rows() ; ii++){
    msg->add_data(mat(ii));
  }
}

inline void WriteVector(const Eigen::VectorXd &mat, VectorMsg *msg) {
  msg->mutable_data()->Reserve(mat.rows());
  for(int ii = 0 ; ii < mat.rows() ; ii++){
    msg->add_data(mat(ii));
  }
}

}  // namespace hal

但是,如果您要跨图书馆进行此操作,则您需要考虑更多内容。还有一个库有一个很好的实现,其中有类型,宽度,高度的枚举,然后是一个字节数组,rowmajor / colmajor等。但我无法再找到它。这些必须被考虑并包含在protobuf中以与矩阵库兼容。对于有关如何执行此操作的一些想法,HAL image protobufimage cpp可能会有所帮助,这可以从opencv源读取/写入,也可以将其视为矩阵。