使用 move::语义将大量向量合并为更大的向量



我有大量可以序列化为array<double, 5>的对象,我们称它们为stuff,我想将所有这些对象合并成一个大vector<double>,称之为data,用于消息传递中离散本地/远程节点之间的同步。

我认为使用移动语义将内容移动到数据中应该比复制数据具有巨大的性能提升,但在测试中,它在调试模式下实际上执行得要慢得多,而在发布模式下则略慢。我在想是否有一种标准方法来做到这一点以获得最佳性能?以下是我使用的实现:

std::vector<std::array<double, 5> > stuff(2000);
std::vector<double> data;
data.reserve(10000);

1)

for (auto & b : stuff) {
data.insert(data.end(), std::make_move_iterator(b.begin()),
std::make_move_iterator(b.end()));
}

2)

for (auto & b : stuff) {
for (auto & item : b) {
data.emplace_back(std::move(item));
}
}

3)

for (auto & b : stuff) {
std::move(b.begin(), b.end(), std::back_inserter(data));
}

4)

for (auto & b : stuff) {
for (const auto & item : b) {
data.emplace_back(item);
}
}

附言: 我正在使用带有-O3 -march=native -mavx标志的g ++

首先,std::move 可以提高性能,但它只会对拥有某种资源的复杂类型这样做。请看这个例子:

class MyVector {
double* data;
size_t size;
...
MyVector(MyVector&& rhs) :
data(rhs.data),
size(rhs.size)
{}
MyVector(const MyVector& rhs) :
data(new double[rhs.size]),
size(rhs.size)
{
std::copy(rhs.data, rhs.data+size, data);
}
...        
};

对于我们的MyVector移动操作会更快,因为可以规避数据的分配和深层复制,只需要一个辅助。我们不会为 size 属性节省任何时间,因为它是要分配的,就像在复制构造函数中一样。 对于不保存任何资源的类型(如示例中的内存),移动语义不会提高性能。所有属性都必须写入新位置,无论我们是否可以删除旧对象,这并不重要。

在您的情况下,您尝试移动double值,无论您是否使用移动语义,都必须将这些值复制到新位置。您看到性能损失的原因可能是因为您阻止编译器对数据执行单个内存副本。执行一个内存复制操作通常比元素复制更快。

做副本的禁食方式很可能是std::memcpy,其次是std::copy,专门用于将std::memcpy用于琐碎的类型。您可能不会看到速度的提高,因为编译器认识到,您希望复制大量双精度并优化代码以使用 memcpy。如果你想找出发生了什么,你可以使用 objdump 或 gdb 检查 asm 代码。

最新更新