我不太熟悉 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/