【发布时间】:2013-11-03 09:41:20
【问题描述】:
假设您想计算给定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 前缀,它可能会多花费几个周期,但仅此而已,对吧?
也许你想这样重写它,它是一样的,只是可能更可重用,对吧?
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 并得到这个 这些参数决定了 ASCII 与非 ASCII 的比率以及非 ASCII 序列的平均长度,但正如您所见,它们并不重要。尝试不同的种子,什么都无所谓。 benchmark 使用 caliper,因此通常的陷阱不适用。结果相当可重复,末尾的小黑条表示最小和最大时间。
有人知道这里发生了什么吗?任何人都可以复制它吗?
【问题讨论】:
-
仅供参考,Java 微基准测试很难正确:ibm.com/developerworks/java/library/j-jtp12214
-
我不明白智能算法比简单算法更智能。它只是使用两个循环而不是一个循环,每个循环基本上都做同样的事情:将每个字符与 256 进行比较。因此算法更复杂,因此可优化性较差。
-
您的做法是正确的:您使用好的工具来衡量每个算法的性能。因此,只需选择最快的一个。试图猜测 JIT 如何优化代码(至少对我而言,但我猜对几乎所有人而言)是一项不可能完成的任务。
-
顺便说一句,ASCII 以 127 结尾,而不是 255。在 unicode 中,128-255 范围是 Latin-1 补充块。
-
@maaartinus,您可能是对的,但是当您分析程序的性能时,尤其是当结果与您的预期不符时,它从来没有好假设的想法。检查一切,不要假设。即使您这次是对的,这种心态在将来排除故障时也会为您提供良好的服务。
标签: java performance