同一函数的以下 2 个版本(基本上尝试通过暴力恢复密码)不会提供相同的性能:
版本 1:
private static final char[] CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
private static final int N_CHARS = CHARS.length;
private static final int MAX_LENGTH = 8;
private static char[] recoverPassword()
{
char word[];
int refi, i, indexes[];
for (int length = 1; length <= MAX_LENGTH; length++)
{
refi = length - 1;
word = new char[length];
indexes = new int[length];
indexes[length - 1] = 1;
while(true)
{
i = length - 1;
while ((++indexes[i]) == N_CHARS)
{
word[i] = CHARS[indexes[i] = 0];
if (--i < 0)
break;
}
if (i < 0)
break;
word[i] = CHARS[indexes[i]];
if (isValid(word))
return word;
}
}
return null;
}
版本 2:
private static final char[] CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
private static final int N_CHARS = CHARS.length;
private static final int MAX_LENGTH = 8;
private static char[] recoverPassword()
{
char word[];
int refi, i, indexes[];
for (int length = 1; length <= MAX_LENGTH; length++)
{
refi = length - 1;
word = new char[length];
indexes = new int[length];
indexes[length - 1] = 1;
while(true)
{
i = refi;
while ((++indexes[i]) == N_CHARS)
{
word[i] = CHARS[indexes[i] = 0];
if (--i < 0)
break;
}
if (i < 0)
break;
word[i] = CHARS[indexes[i]];
if (isValid(word))
return word;
}
}
return null;
}
我希望版本 2 会更快,正如它所做的那样(这是唯一的区别):
i = refi;
...与版本 1 相比:
i = length -1;
然而,事实恰恰相反:版本 1 速度快了 3% 以上! 有人知道为什么吗?这是由于编译器做了一些优化吗?
感谢大家到目前为止的回答。 只是补充一点,目标实际上不是优化这段代码(已经相当优化了),而是更多地从编译器/CPU/架构的角度理解如何解释这种性能差异。 您的回答非常有帮助,再次感谢!
关键
最佳答案
很难在微基准测试中检查这一点,因为如果不读取生成的机器代码,您就无法确定代码是如何优化的,即使 CPU 可以做很多技巧来优化它,例如。它将 RISC 风格指令中的 x86 代码转为实际执行。
一次计算只需一个周期,CPU 最多可以同时执行三个周期。访问 L1 缓存需要 4 个周期,而访问 L2、L3、主存则需要 11、40-75、200 个周期。
在许多情况下,存储值以避免简单计算实际上会更慢。顺便说一句,使用除法和模数是相当昂贵的,在微调代码时缓存这个值是值得的。
关于Java:为什么计算比赋值(int)更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18247523/