Отправка сложных данных с помощью механизма скелета / содержимого в Boost MPI
Кажется, что отправка сложных данных через механизм скелета / контента не работает.
Вот простой код, который показывает проблему:
#include <boost/mpi.hpp>
#include <boost/serialization/complex.hpp>
#include <boost/serialization/vector.hpp>
#include <iostream>
namespace mpi = boost::mpi;
using namespace std;
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
int NN=world.size();
int myid=world.rank();
if (myid == 0)
{
int N = 10;
vector <complex<double> > l(N);
for (int p=1; p!=NN; p++)
{
int taskid=1;
world.send(p, 0, taskid);
world.send(p, 1, mpi::skeleton(l));
}
mpi::content c = mpi::get_content(l);
for (int n = 0; n!=l.size() ; n++)
{
l[n]=complex<double>(1.0,1.0);
}
for (int p=1; p!=NN; p++)
{
world.send(p, 1, c);
}
}
else if (myid == 2)
{
vector <complex<double> > l;
mpi::content c;
world.recv(0, 1, mpi::skeleton(l));
c = mpi::get_content(l);
world.recv(0, 1, c);
for (int n=0; n!=l.size(); n++)
{
cout << l[n] << " ";
}
cout << endl;
}
}
Записи вектора l на выходе не являются (1.0,1.0), но они кажутся неинициализированными. Это происходит, только если используются сложные типы данных И механизм скелета / контента.
Кто-нибудь знает, если это проблема со сборкой, или я делаю что-то не так?
3 ответа
Недавно я столкнулся с подобной проблемой с одним из моих классов, и после некоторого прохождения процедуры сериализации в отладчике, я думаю, я понял, что происходит. Проблема заключается в использовании временных операторов в операторах сериализации. В boost/serialization/complex.hpp функции сериализации выглядят так:
template<class Archive, class T>
inline void save(
Archive & ar,
std::complex< T > const & t,
const unsigned int /* file_version */
){
const T re = t.real();
const T im = t.imag();
ar << boost::serialization::make_nvp("real", re);
ar << boost::serialization::make_nvp("imag", im);
}
template<class Archive, class T>
inline void load(
Archive & ar,
std::complex< T >& t,
const unsigned int /* file_version */
){
T re;
T im;
ar >> boost::serialization::make_nvp("real", re);
ar >> boost::serialization::make_nvp("imag", im);
t = std::complex< T >(re,im);
}
Обратите внимание, что сериализация осуществляется через временные. Функциональность get_content работает путем создания типа данных MPI, который на самом деле представляет собой карту расположения содержимого в памяти. При получении сообщения MPI копирует данные непосредственно в эти местоположения, не вызывая операторов сериализации. Проблема состоит в том, что когда "save" использует временные значения, get_content() не будет получать местоположения фактических данных, но временных значений, поэтому полученные данные не будут помещены в правильное место.
Чтобы работала функция скелета / контента, у меня сложилось впечатление, что функция сохранения (которая вызывается get_content ()) должна напрямую и только сериализовать элементы данных объекта. В этом случае это невозможно, потому что у него нет доступа к внутреннему представлению комплекса. Я думаю, что нужно написать операторы сериализации в качестве членов класса.
(Эти ограничения, по-видимому, вообще не упоминаются в документации Boost::MPI.)
namespace boost {
namespace mpi {
template <>
struct is_mpi_datatype< complex<double> > : mpl::true_ { };
} }
использование этого может решить проблему. В ускоренной оптимизации сериализации
Вот возможное решение проблемы:
Я написал свою собственную сериализацию для сложных типов:
#include <boost/mpi.hpp>
#include <boost/serialization/vector.hpp>
#include <iostream>
namespace mpi = boost::mpi;
using namespace std;
namespace boost
{
namespace serialization
{
template<class Archive>
void serialize(Archive & ar, complex<double> & g, const unsigned int version)
{
ar & g.real();
ar & g.imag();
}
}
}
int main(int argc, char* argv[])
{
mpi::environment env(argc, argv);
mpi::communicator world;
int NN=world.size();
int myid=world.rank();
if (myid == 0)
{
int N = 10;
vector <complex<double> > l(N);
for (int p=1; p!=NN; p++)
{
world.send(p, 1, mpi::skeleton(l));
}
mpi::content c = mpi::get_content(l);
for (int n = 0; n!=l.size() ; n++)
{
l[n]=complex<double>(1.0,1.0);
}
for (int p=1; p!=NN; p++)
{
world.send(p, 1, c);
}
}
else
{
vector <complex<double> > l;
mpi::content c;
world.recv(0, 1, mpi::skeleton(l));
c = mpi::get_content(l);
world.recv(0, 1, c);
for (int n=0; n!=l.size(); n++)
{
cout << l[n] << " ";
}
cout << endl;
}
}