3

在我从事的一个项目中,我必须通过网络来回发送浮点/双精度数组,我使用 Boost.Asio 来处理网络内容,因为我需要异步通信,而这似乎是那里最好的(唯一真实的?)...

发送的数组是浮点数/双精度数,双方都知道类型。AFAIK,浮点存储标准可能存在问题+与 longs/ints、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++ 的经验是有限的,而且我最近才在长时间休息后重新开始编写它......

4

3 回答 3

2

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

于 2012-02-12T09:46:47.033 回答
1

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

Boost.mpi讨论了 boost.serialization 可能的性能优化。特别是,使用

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

宏和 mpi 定义的宏

  • BOOST_IS_MPI_DATATYPE(gps_position)

这些优化似乎效果很好,请参见此

我从来没有使用过protobuff,所以我不能说这个。

于 2011-07-21T11:11:38.783 回答
1

在 github 上有很好的例子。以下是一些可能的资源,用于往返协议缓冲区特征和矩阵:

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

用于存储矩阵的 Protobuf

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];
}

加载到 eigen 并写入 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 图像 protobuf图像 cpp可能会有所帮助,它们从 opencv 源读/写,也可以被认为是一个矩阵。

于 2016-11-12T00:54:18.917 回答