gpt4 book ai didi

java - 对一个简单的程序进行无害的更改后,性能出现奇怪的下降

转载 作者:搜寻专家 更新时间:2023-10-31 19:55:43 26 4
gpt4 key购买 nike

假设您想计算给定的 char[] 包含多少个非 ASCII 字符。想象一下,性能真的很重要,所以我们可以跳过我们最喜欢的 slogan .

最简单的方法显然是

int simpleCount() {
int result = 0;
for (int i = 0; i < string.length; i++) {
result += string[i] >= 128 ? 1 : 0;
}
return result;
}

然后您认为许多输入都是纯 ASCII,分开处理它们可能是个好主意。为简单起见,假设您只写这个

private int skip(int i) {
for (; i < string.length; i++) {
if (string[i] >= 128) break;
}
return i;
}

这样一个简单的方法可能对更复杂的处理有用,在这里它不会有任何坏处,对吧?那么让我们继续

int smartCount() {
int result = 0;
for (int i = skip(0); i < string.length; i++) {
result += string[i] >= 128 ? 1 : 0;
}
return result;
}

它与simpleCount 相同。我称其为“智能”,因为要完成的实际工作更加复杂,因此快速跳过 ASCII 是有意义的。如果没有 ASCII 前缀或非常短的 ASCII 前缀,可能会多花费几个周期,但仅此而已,对吧?

也许你想像这样重写它,它是一样的,只是可能更可重用,对吧?

int smarterCount() {
return finish(skip(0));
}

int finish(int i) {
int result = 0;
for (; i < string.length; i++) {
result += string[i] >= 128 ? 1 : 0;
}
return result;
}

然后你运行了一个benchmark在一些很长的随机字符串上得到这个 img这些参数决定了 ASCII 与非 ASCII 的比率以及非 ASCII 序列的平均长度,但如您所见,它们并不重要。尝试不同的种子和任何无关紧要的事情。 benchmark使用 caliper ,所以通常的陷阱不适用。结果相当可重复,末尾的小黑条表示最小和最大时间。

有人知道这里发生了什么吗?任何人都可以复制它吗?

最佳答案

明白了。

不同之处在于优化器/CPU 预测 for 中的循环次数的可能性。 .如果能够预先预测重复次数,则可以跳过实际检查 i < string.length .因此,优化器需要预先知道 for 循环中的条件成功的频率,因此它必须知道 string.length 的值。和 i .

我通过替换 string.length 做了一个简单的测试使用局部变量,在 setup 中设置一次方法。结果:smarterCount运行时间约为 simpleCount .变更前smarterCountsimpleCount 多花了大约 50% . smartCount没有改变。

当调用另一个方法时,优化器似乎丢失了它必须执行多少循环的信息。这就是为什么 finish()使用常数集立即跑得更快,但不是 smartCount() , 作为 smartCount()不知道什么i将在skip()之后步。所以我做了第二次测试,我从 skip() 复制了循环进入smartCount() .

瞧,这三种方法都在同一时间(800-900 毫秒)内返回。

Different runtimes

关于java - 对一个简单的程序进行无害的更改后,性能出现奇怪的下降,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19751587/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com