0 c++ performance pointers memory-management visual-c++
我在运行大量数据时遇到性能问题.为简单起见,我记下以下代码:
double *a = new double();
for (int i = 0; i < 1000000; i++){
double x = 0;
double y = 0;
for (int j = 0; j < 1000; j++){
x = 1000;
y++;
}
*a = x; //*a = y;
}
Run Code Online (Sandbox Code Playgroud)
这需要将近0毫秒.但是,如果我将y分配给*a:
double *a = new double();
for (int i = 0; i < 1000000; i++){
double x = 0;
double y = 0;
for (int j = 0; j < 1000; j++){
x = 1000;
y++;
}
*a = y; //*a = x;
}
Run Code Online (Sandbox Code Playgroud)
这需要763毫秒,这比第一种情况要长得多.我发现这是由循环中相对更复杂的y计算引起的.但我不知道为什么会这样.如果我改变
*a = y;
Run Code Online (Sandbox Code Playgroud)
至
double temp=y;
*a = temp;
Run Code Online (Sandbox Code Playgroud)
这仍然花费近763毫秒.无论我如何转移价值,似乎我都无法有效地将y的值分配给*a.任何人都可以解释为什么在完成内循环后y与x有显着差异?为什么即使我将y的值转移到其他临时变量,仍然需要很长时间才能将该值赋给*a?(顺便说一句,如果'a'是double而不是指向double的指针,则指定y和x的值之间没有区别.)
double *a = new double();
// OUTER LOOP:
for (int i = 0; i < 1000000; i++){
double x = 0;
double y = 0;
// INNER LOOP:
for (int j = 0; j < 1000; j++){
x = 1000;
y++;
}
*a = x; //*a = y;
}
Run Code Online (Sandbox Code Playgroud)
在你的外环中,你反复指定*a
为x
或y
.
在你的内循环,你要么设置x
到1000
反复,或者你增加y
1000
倍.
现在,编译器知道x=1000
后面的x=1000
内容相当于只执行一次.因此,优化代码非常容易,如下所示:
double *a = new double();
// OUTER LOOP:
for (int i = 0; i < 1000000; i++){
constexpr double x = 1000;
double y = 0;
// INNER LOOP:
for (int j = 0; j < 1000; j++){
y++;
}
*a = x; //*a = y;
}
Run Code Online (Sandbox Code Playgroud)
然后
for (int i = 0; i < 1000000; i++){
double y = 0;
// INNER LOOP:
for (int j = 0; j < 1000; j++){
y++;
}
*a = 1000; //*a = y;
}
Run Code Online (Sandbox Code Playgroud)
然后
for (int i = 0; i < 1000000; i++){
double y = 0;
// INNER LOOP:
for (int j = 0; j < 1000; j++){
y++;
}
//*a = y;
}
*a = 1000;
Run Code Online (Sandbox Code Playgroud)
因为这些操作都是合法的.完成后,您所做的所有工作y
都没有副作用(因为在这种情况下我们从未将其分配*a
),因此变量y
被消除:
for (int i = 0; i < 1000000; i++){
// INNER LOOP:
for (int j = 0; j < 1000; j++){
}
}
*a = 1000;
Run Code Online (Sandbox Code Playgroud)
这使得这些循环变空.并且可以消除空循环(编译器甚至不必证明它们终止!),留下这个:
*a = 1000;
Run Code Online (Sandbox Code Playgroud)
在另一方面,这样做y++
1000
的时候y
是不是通常一样做y += 1000
,由于该可能性y
开始了足够大的浮点舍入导致的问题.在这种情况下,它是不正确的,如添加+1到时将不会发生舍入0.
1000倍,但它是不是真的在一般.因为证明不存在舍入是很难的 - 并且完全正确地更难实现 - 编译器编写者可能没有处理这种情况.
这留下了一个更复杂的代码来进行优化,编译器很难确定循环的每次迭代都是完全相同的,因此您已经观察到优化器失败了.
在这种情况下它可以优化多少,我们必须检查反汇编.