如果我将一次迭代变量声明为类成员,我想我会节省一些时间:
struct Foo {
int i;
void method1() {
for(i=0; i<A; ++i) ...
}
void method2() {
for(i=0; i<B; ++i) ...
}
} foo;
然而,这似乎比cca快了20%
struct Foo {
void method1() {
for(int i=0; i<A; ++i) ...
}
void method2() {
for(int i=0; i<B; ++i) ...
}
} foo;
在此代码中
void loop() { // Arduino loops
foo.method1();
foo.method2();
}
你能解释性能差异吗?
(我需要在Arduino上运行许多简单的paralel“进程”,这样的微优化会产生影响。)
答案 0 :(得分:8)
当你在循环中声明你的循环变量时,它的范围很窄。编译器可以随时将它保存在寄存器中,因此它甚至不会被提交到内存中。
当您将循环变量声明为实例变量时,编译器没有这种灵活性。它必须将变量保存在内存中,以防某些方法需要检查其状态。例如,如果您在第一个代码示例中执行此操作
void method2() {
for(i=0; i<B; ++i) { method3(); }
}
void method3() {
printf("%d\n", i);
}
i
中method3
的值必须随着循环的进行而改变。编译器无法将所有副作用提交到内存。此外,当你从i
回来时,它不能假设method3
保持不变,这进一步增加了内存访问次数。
处理内存中的更新比执行基于寄存器的变量更新需要更多的CPU周期。这就是为什么将循环变量限定为循环级别总是一个好主意。
答案 1 :(得分:2)
你能解释性能差异吗?
对于这种性能差异我可以得出的最合理的解释是:
数据成员 i
在全局内存中声明,不能一直保存在寄存器中,因此对它的操作比循环上的操作要慢变量 i
由于范围非常广泛(数据成员i
必须满足该类的所有成员函数)。
@DarioOO补充道:
此外,编译器不能将其临时存储在a中 注册因为
method3()
可能抛出一个异常离开对象 在一个不需要的状态(因为理论上没有人阻止你 写int k=this->i; for(k=0;k<A;k++)method3(); this->i=k;
。那段代码 几乎和局部变量一样快,但你必须坚持下去method3()
抛出时的帐户(我相信当有保证时) 不抛出编译器会优化-O3
或-O4
验证)