幾種std::vector訪問方法的效率

http://www.sf.org.cn/Article/base/200708/20426.html

幾種std::vector訪問方法的效率
作者:Jarod    文章來源:Jarod 的半個程序員    更新時間:2007-8-20 11:51:28
#define _SECURE_SCL 0

#include 
<boost/foreach.hpp>
#include <list>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <time.h>
#include <stdio.h>

using namespace std;

template<typename Container>

void generate(typename Container & v) {
    size_t size =
 v.size();
    for (size_t i=0; i< size ; ++i) 
{
        v[i] = i;//rand();

    }

}


struct case1 {
int operator() (const vector<int> & v, size_t size) 
{
    int sum=0
;
    vector<int>::const_iterator it =
 v.begin();
    for (size_t i=0; i< size; ++i, ++it ) 
{
        sum += *
it;
    }

    return sum;
}
}
;

struct case2 
{
int operator() (const vector<int> & v, size_t size) 
{
    int sum=0
;
    for(size_t i=0; i< size; ++i) 
{
        sum +=
 v[i];
    }

    return sum;
}
}
;

struct case3 
{
int operator() (const vector<int> & v, size_t size) 
{
    int sum=0
;
    BOOST_FOREACH(int x, v) 
{
        sum +=
 x;
    }
    
    return
 sum;
}
}
;

struct case4 
{
int operator() (const vector<int> & v, size_t size) 
{
    int sum=0
;
    for (vector<int>::const_iterator it =
 v.begin();
        it !=
 v.end();
        ++
it
        ) 
{
        sum += *
it;
    }

    return sum;
}
}
;

template<typename T>

__int64 Do(typename T op, vector<int> &v, int M) {
    size_t size =
 v.size();
    __int64 sum = 0
;
    for (int i=0;i<M;++i) 
{
        generate(v);
        sum +=
 op(v, size);
    }

    return sum;
}


int main() {
    srand(static_cast<unsigned int>
(time(NULL)) );

    vector<int> v(65536
);
    int M= 10000
;
    printf("1 : %d "
, Do(case1(),v,M));
    printf("2 : %d "
, Do(case2(),v,M));
    printf("3 : %d "
, Do(case3(),v,M));
    printf("4 : %d "
, Do(case4(),v,M));
    
}

 

debug模式下:

先不看case3,因爲BOOST_FOREACH的效率在debug模式下與其它相差較大。Case4也不看

 

case1與case2的效率基本相同。

注意case1中的主要操作是*和++;而case2中主要是[]和size(),特別的,size()還可以改STL原碼除去,這樣case2將大爲縮短時間。

 

 

而在Release模式下,case2比case1略優:

 

 

通過跟蹤可以發現:

vector的size()函數裏使用了一個三元操作符?:,而不是直接返回size,但這裏沒有安全檢查。

operator*()與++()中,即便在release版本中,都會包含指針檢查(ASM中的__imp___invalid_parameter_noinfo部分),每個操作都包括_SCL_SECURE_VALIDATE及_SCL_SECURE_VALIDATE_RANGE,但這些消耗的時間不多。兩個檢查若沒通過都會轉到__imp___invalid_parameter_noinfo中。

 

struct case1 {

int operator() (const vector<int> & v, size_t size) {

     int sum=0;

     vector<int>::const_iterator it = v.begin(); // 一個檢查

     for (size_t i=0; i< size; ++i, ++it ) { // 一個檢查

         sum += *it;   // 一個檢查

     }

     return sum;

}};

 

struct case2 {

int operator() (const vector<int> & v, size_t size) {

     int sum=0;

     for(size_t i=0; i< size; ++i) {

         sum += v[i];//一個檢查,但是包含求size()的檢查

     }

     return sum;

}};

 

在[]操作中,包括一個_SCL_SECURE_VALIDATE_RANGE(_Pos < size()),而求size()費時。

 

Case4中包含更多的安全檢查。

 

要消除這些安全查檢,可以定義_SECURE_SCL爲0。

消除檢查之後,得到如下結果。兩種方式的效率已經相當接近,但case1還是略優。改寫後的Case3和4也與前兩者接近。

剩下的只能用vtune來分析每個操作了。

 

結論:不論用哪種方法,release版的效率都差不多。

1.       少使用size()。

2.       使用[]訪問,使調試與發佈的運行效率接近。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章