简体   繁体   English

std :: vector :: reserve性能惩罚

[英]std::vector::reserve performance penalty

inline void add(const DataStruct& rhs) {
   using namespace boost::assign;
   vec.reserve(vec.size() + 3);
   vec += rhs.a, rhs.b, rhs.c;
}

The above function was executed for about 17000 times and it performed (as far as I can see. There was some transformation involved) about 2 magnitudes worse with the call to vector::reserve. 上述功能是为约17000倍执行,其执行(据我可以看到。有一些改造涉及)约2个数量级更糟糕的呼叫矢量::储备。

I always was under the impression that reserve can speed up push_back even for small values but this doesn't seem true and I can't find any obvious reasons why it shouldn't be this way. 我总是认为保留可以加速push_back,即使是小值,但这似乎不正确,我找不到任何明显的原因,为什么它不应该这样。 Does reserve prevent the inlining of the function? 保留是否会阻止功能的内联? Is the call to size() too expensive? 对size()的调用是否过于昂贵? Does this depend on the platform? 这取决于平台吗? I'll try and code up some small benchmark to confirm this in a clean environment. 我会尝试编写一些小基准来在干净的环境中确认这一点。

Compiler: gcc (GCC) 4.4.2 with -g -O2 编译器: gcc (GCC) 4.4.2带-g -O2

GCC implementation of reserve() will allocate exact number of elements, while push_back() will grow internal buffer exponentially by doubling it, so you are defeating the exponential growth and forcing reallocation/copy on each iteration. reserve() GCC实现将分配确切数量的元素,而push_back()将通过加倍来指数增长内部缓冲区,因此您正在击败指数增长并在每次迭代时强制重新分配/复制。 Run your test under ltrace or valgrind and see the number of malloc() calls. ltracevalgrind下运行测试,看看malloc()调用的数量。

You only use reserve() if you know in advance the number of elements. 如果事先知道元素的数量,则只使用reserve() In that case reserve() space for all elements at once. 在那种情况下,一次为所有元素reserve()空间。

Otherwise just use push_back() and rely on the default strategy - it will reallocate exponentially and greatly reduce the number of reallocations at a cost of slightly suboptimal memory consumption. 否则只需使用push_back()并依赖于默认策略 - 它将以指数方式重新分配,并以稍微不理想的内存消耗为代价大大减少重新分配的数量。

Use only reserve if you know in advance how much place it will use. 如果您事先知道将使用多少地方,请仅使用保留。

Reserve will need to copy your whole vector... 保留将需要复制你的整个矢量......

If you do a push_back and the vector is too small, then it will do a reserve (vec.size()*2). 如果你执行push_back并且向量太小,那么它将执行保留(vec.size()* 2)。

If you don't know beforehand how big your vector is going to be and if you need random access, consider using std::deque. 如果你事先不知道你的矢量有多大,如果你需要随机访问,可以考虑使用std :: deque。

When std::vector needs to reallocate it grows its allocation size by N*2, where n is its current size. 当std :: vector需要重新分配时,它的分配大小增加N * 2,其中n是其当前大小。 This results in a logarithmic number of reallocs as the vector grows. 当矢量增长时,这导致对数的realloc。

If instead the std::vector grew its allocated space by a constant amount, the number of reallocs would grow linearly as the vector grows. 相反,如果std :: vector以恒定量增加其分配的空间,则reallocs的数量将随着向量的增长而线性增长。

What you've done is essentially cause the vector to grow by a constant amount 3, meaning linear growth. 你所做的实际上是导致向量增长3,意味着线性增长。 Linear is obviously worse that logarithmic, especially with big numbers. 线性显然比对数更差,特别是对于大数字。

Generally, the only growth better than logarithmic is constant. 通常,唯一比对数增长更好的增长是不变的。 That is why the standards committee created the reserve method. 这就是标准委员会创建储备方法的原因。 If you can avoid all reallocs (constant) you will perform better than the default logarithmic behavior. 如果您可以避免所有reallocs(常量),那么您将比默认的对数行为更好。

That said you may want to consider Herb Sutter's comments about preferring std::deque over vector www.gotw.ca/gotw/054.htm 那说你可能想要考虑Herb Sutter关于更喜欢std :: deque而不是矢量www.gotw.ca/gotw/054.htm的评论

Move the reserve outside of the add. 将保留移动到添加之外。

Each time you invoke "add", you are reserving atleast 3 extra elements. 每次调用“add”时,都会保留至少3个额外元素。 Depending on the implementation of vector, this could be increasing the size of the backing array almost every time you call "add". 根据vector的实现,这几乎可以在每次调用“add”时增加后备数组的大小。 That is would definately cause the performance difference that you describe. 这肯定会导致您描述的性能差异。

The correct way to use reserve is something like: 使用保留的正确方法是这样的:

vec.reserve(max*3);
for(int i=0; i<max; i++)
   add(i);

If you profiled the code I bet you would see that the += IS very fast, the problem is the reserve is killing you. 如果你描述了我打赌的代码,你会发现+ = IS非常快,问题是保留会杀了你。 You should really only use reserve when you have some knowledge of how big the vector will grow to. 当你对向量增长到多大有所了解时,你应该只使用reserve。 If you can guess ahead of time then do ONE reserve, otherwise just go with the default push_back. 如果你可以提前猜测然后做一个保留,否则只需使用默认的push_back。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM