c++函数性能中的静态变量

标签 c++

我不太熟悉 C++ 函数中的静态变量。我知道它只初始化一次。例如

void func(map<int, int>& m){
   static int a = m[0];
}

我希望 static int a = m[0] 在我第一次调用该函数时只执行一次,但在我看来,每次调用该函数时,执行 m[0] 都会花费一些时间。这是我做的一项测试。程序本身没有意义(它总是返回相同的数字)但只是想展示性能作为例子

    double getDirect(int i, map<int, double>& m){
    static double res = i;
    return res;
    }

    double getFromMap(int i, map<int, double>& m){
    static double res = m[i];
    return res;
    }

在主函数中

clock_t t;
t = clock();
long long i = 0;
map<int, double> m;
for(int i = 0; i < 10; i++){
    m.insert(make_pair(i, i));
}
#pragma omp parallel for private(i)
for(i = 0; i < size; i++){
    for(int j = 0; j < 10; j++)
        double res = getDirect(j, m);
}

t = clock()-t;
cout << " It cost " << t << " clicks (" << ((float)t) / CLOCKS_PER_SEC << " sec) to run." << endl;

t = clock();
#pragma omp parallel for private(i)
for(i = 0; i < size; i++){
    for(int j = 0; j < 10; j++)
        double res = getFromMap(j, m);        
}
t = clock()-t;
cout << " It cost " << t << " clicks (" << ((float)t) / CLOCKS_PER_SEC << " sec) to run." << endl;

我希望两者之间的时间非常相似。但是结果是

运行需要 14055 次点击(14.055 秒)。 运行需要 150636 次点击(150.636 秒)。

getFromMap 要慢得多。这是因为m[i]还是每次都执行?若否,原因为何?如果是这样,绕过这种性能成本的好方法是什么?谢谢。

这里是一些跟进。我得到了汇编代码\

    static double res = m[i];
000000013F83D454  mov         eax,104h  
000000013F83D459  mov         eax,eax  
000000013F83D45B  mov         ecx,dword ptr [_tls_index (013F8503C8h)]  
000000013F83D461  mov         rdx,qword ptr gs:[58h]  
000000013F83D46A  mov         rcx,qword ptr [rdx+rcx*8]  
000000013F83D46E  mov         eax,dword ptr [rax+rcx]  
000000013F83D471  cmp         dword ptr [res+0Ch (013F85035Ch)],eax  
000000013F83D477  jle         getFromMap+0A9h (013F83D4B9h)  
000000013F83D479  lea         rcx,[res+0Ch (013F85035Ch)]  
000000013F83D480  call        _Init_thread_header (013F831640h)  
000000013F83D485  cmp         dword ptr [res+0Ch (013F85035Ch)],0FFFFFFFFh  
000000013F83D48C  jne         getFromMap+0A9h (013F83D4B9h)  
000000013F83D48E  lea         rdx,[i]  
000000013F83D495  mov         rcx,qword ptr [m]  
000000013F83D49C  call        std::map<int,double,std::less<int>,std::allocator<std::pair<int const ,double> > >::operator[] (013F831320h)  
000000013F83D4A1  movsd       xmm0,mmword ptr [rax]  
000000013F83D4A5  movsd       mmword ptr [res (013F850360h)],xmm0  
000000013F83D4AD  lea         rcx,[res+0Ch (013F85035Ch)]  
000000013F83D4B4  call        _Init_thread_footer (013F8314C4h)

确实好像m[i]在第一次之后还是被调用了。我也做了一个较小尺寸的单线程测试,但差异更大(大约100的比率)。

关于如何设置 visual studio 2012 以使其在第一次后停止调用 m[i] 的任何想法?非常感谢您的帮助

最佳答案

拥有函数局部静态变量会稍微惩罚你。由于静态值需要初始化一次,而且只有一次,所以必须有一个标志,在每次函数执行时都会检查,在第一次进入函数之前设置为“yes, please initialize”并在此类初始化发生后重置为“不,请不再初始化”。

否则,编译器将无法保证一次初始化。

但是,编译器向您保证,一旦变量被初始化,就不会再进行初始化,并且会跳过声明:https://en.cppreference.com/w/cpp/language/storage_duration#Static_local_variables

我们可以查看示例代码生成以使用编译器确认此假设:https://gcc.godbolt.org/z/Q-Dni_很明显,如果变量已经初始化,则将跳过声明并且不会调用 k。结论:你的时间差来自别处。

关于c++函数性能中的静态变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56467265/

相关文章:

c++ - 从 Vector 中删除行

c++ - 在 Sqlite C++ 中插入以下语句

c++ - std::find 包含指针的 vector

c++ - QMainWindow centralWidget 边框

c++ - openMP lastprivate 和 firstprivate 到同一个变量

c++ 在运行时检查对象是否实现了接口(interface)

c++ - 嵌套包含语句,便于 c/c++ 编程

c++ - boost::algorithm::join 返回值的范围是什么?

c++ - 模板 friend 类 : Forward Declaration or. ..?

c++ - 查明 C++ 对象是否可调用