我有一个现有的算法,如果可能的话我需要稍微优化它。目前,此算法中的大量更改不是一种选择。该算法适用于std::vector< std::vector<unsigned char> >
的实例。它看起来像这样:
typedef std::vector<unsigned char> internal_vector_t;
std::vector< internal_vector_t > internal_vectors;
while (fetching lots of records) {
internal_vector_t tmp;
// reads 1Mb of chars in tmp...
internal_vectors.push_back(tmp);
// some more work
}
// use this internal_vectors
该算法使用push_back()在internal_vector_t的internal_vectors
个实例中插入了很多次。 internal_vector_t的大多数实例的大小为1 Mb 。由于internal_vectors
的大小未知,因此事先没有预留()。
我不明白的第一件事是当internal_vectors
达到其当前容量时发生的事情,需要分配一个新块并将其当前内容复制到更大的内存块中。由于大多数块的大小都是1Mb,因此复制操作很长。 我是否应该期望编译器(gcc 4.3,MS VC ++ 2008)能够设法优化它以避免复制?
如果无法避免复制,会更改为std::deque
帮助吗?我认为std :: deque因为我仍然需要通过像internal_vectors [10]这样的索引来访问。像这样:
typedef std::vector<unsigned char> internal_vector_t;
std::deque< internal_vector_t > internal_vectors;
// the same while
据我所知,std::deque
不需要重新定位曾经分配的内容。我是对的,std::deque
在这种情况下会重新减少分配和复制push_backs吗?
<小时/> 的更新
2)我已经分析了使用std::deque< std::vector<unsigned char> >
的算法版本,我发现它的性能更好。
3)我还使用了Mark Ransom建议的swap
。使用这改善了性能:
internal_vector_t tmp;
internal_vectors.push_back(empty);
tmp.swap(internal_vectors.back());
答案 0 :(得分:3)
MSVC9为其标准容器实现了称为“swaptimization”的东西。这是一个较弱的移动语义版本。当外部矢量调整大小时,不复制内部矢量。
但是,您最好只需将编译器升级到MSVC10或GCC(4.5,我认为是),它将为您提供移动语义,从而使这些操作更加高效。当然,std::deque
可能仍然是更智能的容器,但移动语义在许多地方都具有性能优势。
答案 1 :(得分:2)
每次向internal_vector_t
插入internal_vectors
时,都会复制internal_vector_t
。无论您使用vector
还是deque
,都是如此。标准容器总是复制您要插入的对象。
您可以通过插入空internal_vector_t
然后swap
插入对象的内容以及您想要插入的内容来消除复制。
有时,矢量需要在插入过程中耗尽空间时自行调整大小,这会导致再次复制对象。只要你总是在开头或结尾插入,deque就会消除它。
编辑:我上面给出的建议可以通过这些代码更改进行汇总。此代码应避免复制大型矢量。
typedef std::vector<unsigned char> internal_vector_t;
std::deque< internal_vector_t > internal_vectors;
internal_vector_t empty;
while (fetching lots of records) {
internal_vector_t tmp;
// reads 1Mb of chars in tmp...
internal_vectors.push_back(empty);
tmp.swap(internal_vectors.back());
// some more work
}
答案 2 :(得分:1)
std::deque
不会连续存储它的元素 - 它将存储区分为一系列常量大小的“块”。这意味着当std::deque
用完容量时,它只需要分配一个常量大小的新块 - 它不需要重新分配它的整个内部缓冲区并移动它所有的现有元素。
std::vector
确实保持连续存储,因此当它耗尽容量并重新分配时,它确实需要移动所有现有元素 - 这可能很昂贵。
std::vector
对于其重新分配方案是“聪明的”,根据几何系列分配块(通常将容量加倍或增加1.5等)。这意味着不会经常重新分配。
std::deque
可能更有效,因为在重新分配确实发生时它的工作量会减少。与往常一样,您必须进行基准测试以获得任何实数。
您的代码可能会在其他方面进一步改进。似乎在while
循环的每次迭代中,您都在创建一个新的internal_vector_t tmp
。在循环外声明这个并且在每次迭代时只是::clear()
它的存储可能更有效。每次拨打tmp
时,您也会复制整个internal_vectors.push_back(tmp)
向量 - 您可以通过tmp
移动internal_vectors.push_back(std::move(tmp))
向量来改善这一点 - 这只会复制一些指示。
希望这有帮助。
答案 3 :(得分:0)
您是否正在索引外部向量?如果没有,std::list<std::vector<unsigned char> >
怎么样?
答案 4 :(得分:0)
取决于实施,出队可能更有效。与向量不同,出队不能保证连续存储,因此可以分配几个单独的内存块。因此,它可以分配更多内存而无需移动已添加的元素。您应该尝试并测量影响。