首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >向量索引总是更快吗?

向量索引总是更快吗?
EN

Stack Overflow用户
提问于 2012-03-16 09:57:24
回答 4查看 658关注 0票数 2

当使用std::向量时,通过索引遍历所有向量元素的速度总是比迭代器快吗?

我写了简单愚蠢的测试,VS 2010,优化是禁用的。

代码语言:javascript
复制
#include <vector>
#include <iostream>
#include <ctime>

const int SIZE = 100000;    

int main()
{    
    std::vector<int> vInt;
    int i, temp;
    srand(time(0));
    for(i = 0; i<SIZE; i++)
        vInt.push_back(rand());

    time_t startTime, endTime;
    std::vector<int>::iterator it = vInt.begin(), itEnd = vInt.end();
startTime = clock();
for( ; it != itEnd; it++)
        temp = *it;
    endTime = clock();
    std::cout<<"Result for iterator: "<<endTime - startTime;

    i = 0;
    int size = vInt.size();
    startTime = clock();
    for(; i<size; i++)
        temp = vInt[i];
    endTime = clock();
    std::cout<<"\nResult for index: "<<endTime - startTime;    

    return 0;
}

调试模式:

没有优化的结果是

代码语言:javascript
复制
Result for iterator: 143
Result for index: 5

对于const int大小= 1000;

代码语言:javascript
复制
Result for iterator: 0
Result for index: 0

对于const大小= 10000;

代码语言:javascript
复制
Result for iterator: 15
Result for index: 2

对于const大小= 1000000;

代码语言:javascript
复制
Result for iterator: 1377
Result for index: 53

带有标志的/O2

对于const大小= 10000;

代码语言:javascript
复制
Result for iterator: 0 - 2
Result for index: 0

对于const大小= 100000;

代码语言:javascript
复制
Result for iterator: 12 - 15
Result for index: 0

对于const大小= 1000000;

代码语言:javascript
复制
Result for iterator: 133 - 142
Result for index: 0 - 3

因此,最好总是使用向量索引?

更新

释放模式

使用/O2标志,所有结果都为0。

禁用优化时,/Od索引更快

对于const大小= 100000000;

代码语言:javascript
复制
Result for iterator: 2182
Result for index: 472

对于const大小= 1000000;

代码语言:javascript
复制
Result for iterator: 22
Result for index: 5

对于const大小= 100000;

代码语言:javascript
复制
Result for iterator: 2 - 3
Result for index: 0 - 1
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-03-16 12:42:24

第一件事是,对于用例,您应该使用任何习惯用法。如果您正在迭代,我将使用迭代器,如果您正在执行随机访问,那么索引。

现在是实际的问题。性能是很难的,即使是衡量性能也是一个很难的问题,它要求你清楚地知道你想要测量什么,如何测量,以及不同的事情将如何影响你的测试。理想情况下,您希望隔离测试,以便度量尽可能精确,然后多次运行测试以验证结果是否一致。您甚至不应该考虑用完全优化的代码来度量性能,最好是使用真正的程序。如果您处于调试模式,并且程序运行缓慢,最好的优化方法就是在发布模式下编译,增加优化级别,减少库中的调试结构。所有这些改进都是免费的。

在您的测试中,有太多的未知数和变量,实际上无法从中得到任何结果。编译器标志和选项可能会产生很大的影响,因此了解如何使编译器生成更快的代码。向量迭代器的一个简单实现是一个普通指针,因此您可以使用它获得基本度量:

代码语言:javascript
复制
int *it=&v[0], *end=it+v.size();
for (; it!=end; ++it) temp=*it;

这将为您提供一个比较迭代器的基线。迭代器与此基线之间的性能差异是由于您的编译器/库供应商用于调试的额外检查造成的。阅读有关如何禁用它们的文档。还请注意,您的步骤(it++)需要创建it的一个副本,在指针的情况下基本上没有效果,但是如果迭代器保持任何状态,则it++的成本将主导整个循环。总是喜欢++it

下一件事是你想要测量什么,编译器认为你需要什么。您希望度量迭代,但编译器不知道,它只看到您的代码,优化器将尽力生成尽可能快的等效代码。只使用其中一个循环,编译器就可以意识到整个迭代除了将temp设置为v[v.size()-1]之外没有任何副作用,在最坏的情况下(为了您的度量),它实际上可以执行转换,完全删除循环,这将导致我们进入下一个点:

魔鬼就在细节里。我的猜测是,在一般情况下,您的意图是度量迭代的相对成本,但是您的程序是测量在一个恒定大小的向量上迭代的成本。这有什么关系?编译器执行循环展开以尽可能避免测试成本。如果编译器知道您的循环总是包含多个X迭代,那么它只能在每个X步骤中的一个步骤中测试循环完成。优化不能保证,在应用程序的一般情况下,编译器将不知道迭代次数,因此您应该确保测试不会为编译器提供比实际程序中更多的优化机会。在这两种情况下,您希望确保编译器没有在实际情况下没有的额外信息,也就是说,您希望隐藏有关测试的知识,并迫使它集中精力解决问题。我建议您将循环移动到另一个转换单元中的函数中,通过引用传递向量,并确保它不能避免循环(以整数为参数,应用带有向量中的临时和每个元素的二进制运算符,将所有操作的结果返回给调用者;在处理该函数时,编译器希望不能做任何太聪明的事情)。

但最重要的是,我必须让你回到第一段,做什么是惯用的。编译器是针对惯用代码进行优化的,当/如果需要性能时,他们将做正确的事情。这个答案中的循环的性能,或者问题中的两个循环对于优化的构建中未经检查的迭代器的性能是一样的,并不是迭代本身的成本通常会对您的应用程序的性能产生任何影响。

票数 5
EN

Stack Overflow用户

发布于 2012-03-16 09:59:55

否,这取决于编译器和优化标志设置的编译。

即使您发现编译器总是为索引生成更快的代码,也不应该得出迭代器无用的结论。迭代器的优点是它们为所有STL容器提供了统一的接口,这意味着您可以编写一个通用的模板函数,通过接受一对迭代器,它不仅能够处理向量,而且可以使用链接列表和其他容器。

另外,您应该使用前增量运算符而不是后增量运算符,这应该更快:

代码语言:javascript
复制
for( ; it != itEnd; ++it)
票数 3
EN

Stack Overflow用户

发布于 2012-03-16 10:06:55

由于缓存效果,这种比较是不公平的。

首先,在使用VS的情况下,以“释放”模式编译。或者gcc里的-O2

在使用迭代器访问数组元素之后,大多数元素将被缓存。因此,当您立即使用索引访问它们时,缓存已经“升温”了。尝试在两次单独的运行中这样做:一次只使用迭代器,另一次仅使用索引。另外,尝试一个更大的数据集,比如1GB。由于clock不是一个非常细粒度的定时器,所以您可能也需要使用rdtsc

费伊,这是a thread talking about stl:vector iterator vs. index.

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9735113

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档