【发布时间】:2017-11-04 04:16:36
【问题描述】:
我有一个显示非常奇怪结果的微基准:
@BenchmarkMode(Mode.Throughput)
@Fork(1)
@State(Scope.Thread)
@Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS, batchSize = 1000)
@Measurement(iterations = 40, time = 1, timeUnit = TimeUnit.SECONDS, batchSize = 1000)
public class Chaining {
private String a1 = "111111111111111111111111";
private String a2 = "222222222222222222222222";
private String a3 = "333333333333333333333333";
@Benchmark
public String typicalChaining() {
return new StringBuilder().append(a1).append(a2).append(a3).toString();
}
@Benchmark
public String noChaining() {
StringBuilder sb = new StringBuilder();
sb.append(a1);
sb.append(a2);
sb.append(a3);
return sb.toString();
}
}
我希望两个测试的结果相同或至少非常接近。但是,差异几乎是 5 倍:
# Run complete. Total time: 00:01:41
Benchmark Mode Cnt Score Error Units
Chaining.noChaining thrpt 40 8538.236 ± 209.924 ops/s
Chaining.typicalChaining thrpt 40 36729.523 ± 988.936 ops/s
有人知道这怎么可能吗?
【问题讨论】:
-
也许它有一个针对链式 .append 调用的优化规则,它可以一次构造整个字符串?这很有意义。
-
@Mints97 编译器不应该对常规的 sb.append() 结构做同样的事情吗?
-
@JarrodRoberson 我的期望是完全正确的。你不会期待同样的吗?它几乎是相同的代码。即使链接生成的字节码也更少。 5倍的差距?没办法。
-
有趣的是,如果您在关闭 JIT 的情况下运行此程序,它们将按预期工作。 (顺便说一句,
-Djava.compiler=NONE)。每个基准测试的结果几乎相同(而且速度要慢得多)。 -
“我的期望是完全正确的”,但结果却不是你所期望的。你我对“完全正确”的定义不同。
标签: java performance microbenchmark jmh