矢量插入与push_back性能问题

vector insert vs push_back performance issue

本文关键字:back 性能 问题 push 插入      更新时间:2023-10-16

当我分析我的程序时,我发现了一个瓶颈:

for (int i = 0; i < len; ++i) {
    vec->push_back(buffer[i]);
}

for循环位于一个称为100k次的函数中。用以下代码替换它后,性能提升是巨大的。(上面的代码占用了总时间的 10%。下面的代码需要 0.34%(

vec->insert(vec->end(), buffer, buffer + len);

所讨论的向量具有以下类型:vector<char>* vec

谁能解释一下为什么第二个版本要快得多?

我也尝试在第一个版本中保留空间,但没有明显的改进。

如果没有大量的数据,就很难明确地说出为什么一段重要的代码比另一段执行得更快,尤其是当涉及第三方代码(在这种情况下是内部vector代码(时。但你通常可以做一些猜测。

既然你说提前reserve没有区别,我的猜测是它只是归结为所需的操作数量。在你的原始代码中,作为第一近似值,总是会有len索引操作到bufferlen调用push_back *,以及运行循环的一些开销。但是,对insert的调用不一定如此。该函数的朴素实现可能只是遍历迭代器,并为每个值调用push_back,在这种情况下,您希望看到大致相同的性能。但是,更精明的实现可能会意识到该操作归结为复制单个连续的 len 字节运行,并利用机器指令,这些指令可以有效地将其作为单个操作实现(如果初始缓冲区大小太小,则可能之前会调整大小/复制(。但确定的唯一方法是查看所涉及的实际标准库和/或机器代码。

没有提到你正在使用什么编译器,但只是为了它,我在VS2012中实现了类似于你的代码的东西并跟踪了它。 insert最终确实利用了一次调用来执行复制memmove


*这是一个近似值,因为如果push_back作为内联函数实现,并且您的编译器设置允许它被内联,则优化器可能会在该循环中度过一个现场日。当我说如果没有大量具体数据,关于性能的推理可能会很棘手时,我得到了这种事情。

Vector 使用数组作为其底层存储。所以,它会自动在到达阵列末尾之前将其数组大小扩展 2 倍同时使用push_back等方法。

但是在插入的情况下,vector 将为插入准备足够的存储空间,因为 vector 知道将插入多少个元素。这意味着只发生 1 次扩展。