为啥使用指针的 STL 算法比 std::vector 迭代器快得多?
Posted
技术标签:
【中文标题】为啥使用指针的 STL 算法比 std::vector 迭代器快得多?【英文标题】:Why are STL algorithms much faster with pointers than std::vector iterators?为什么使用指针的 STL 算法比 std::vector 迭代器快得多? 【发布时间】:2015-11-26 11:45:53 【问题描述】:当std::nth_element()
被赋予指针而不是迭代器时,为什么它运行得这么快?我希望 std::vector
和 STL 算法得到相当优化,但我的测量结果显示,当我将迭代器更改为指针时,执行时间下降了 75%。
使用迭代器,以下代码(不包括向量的分配)在 1200 毫秒内运行:
std::vector<uint16_t> data(/* 50 million values */);
const double alfa = 0.01;
const double beta = 0.95;
std::nth_element(data.begin(), data.begin() + int(data.size() * alfa), data.end());
const uint16_t x = *(data.begin() + int(data.size() * alfa));
std::nth_element(data.begin(), data.begin() + int(data.size() * beta), data.end());
const uint16_t y = *(data.begin() + int(data.size() * beta));
使用指针,以下代码(不包括向量的分配)在 350 毫秒内运行:
std::vector<uint16_t> data(/* 50 million values */);
const double alfa = 0.01;
const double beta = 0.95;
std::nth_element(&data.front(), &data.front() + int(data.size() * alfa),
&data.front() + data.size());
const uint16_t x = *(data.begin() + int(data.size() * alfa));
std::nth_element(&data.front(), &data.front() + int(data.size() * beta),
&data.front() + data.size());
const uint16_t y = *(data.begin() + int(data.size() * beta));
我也观察到std::sort()
的速度增加类似。这些示例使用 Embarcadero C++ Builder XE8 版本 22.0.19027.8951、发布版本和“生成尽可能快的代码”设置进行编译。这些测试在不同的执行过程中运行,因此它们不应相互影响。
【问题讨论】:
作为旁注:您为一个只能有 65536 个不同值的类型存储 5000 万个值。考虑为任务使用更好的数据结构。 您是否使用不同的编译器尝试了相同的基准测试?我可以想象编译器不会查看与迭代器一起使用的 [希望内联] 函数。当编译器确实检测到它是连续内存时(因为编译器通常可以用于指针,据我所知,也可以用于std::vector
迭代器),它可能能够对一些操作进行矢量化以获得性能(这可能很有趣通过选择性地禁用矢量化来查看改进是否归结为矢量化;我知道gcc 可以选择性地禁用此优化)。
@rozina:这对我来说非常清楚。
我的猜测是编译器要么在优化方面做得不好,要么你在调试模式下构建,编译器使用特殊的调试(慢)版本的 STL 容器。
@rozina:您存储每个元素的计数。 en.wikipedia.org/wiki/Counting_sort
【参考方案1】:
我的猜测是编译器要么在优化方面做得不好,要么你在调试模式下构建并且编译器使用特殊的调试(慢)版本的 STL 容器。
【讨论】:
我经历了所有的麻烦,看看 gcc 和 llvm 对此做了什么,只是为了看到问题已经解决。嗬!在测试这个时,我实际上得到了一些奇怪的行为。我知道我第二个运行的版本更快。 @GuyGreer 基准测试有一定的艺术,我仍在学习陷阱。有时我可以通过在开始时分配一大块内存然后立即释放它来加速我的基准测试。以上是关于为啥使用指针的 STL 算法比 std::vector 迭代器快得多?的主要内容,如果未能解决你的问题,请参考以下文章