选项1:
boolean isFirst = true;
for (CardType cardType : cardTypes) {
if (!isFirst) {
descriptionBuilder.append(" or ");
} else {
isFirst = false;
}
//other code not relevant to this theoretical question
}
选项2:
boolean isFirst = true;
for (CardType cardType : cardTypes) {
if (!isFirst) {
descriptionBuilder.append(" or ");
}
isFirst = false;
//other code not relevant to this theoretical question
}
我的分析:两个代码都有相同的语义。
第一个代码)我不确定这个代码是否有两个分支(就分支预测器而言)或一个分支。我正在调查http://en.wikipedia.org/wiki/X86_instruction_listings但是无法弄清楚有一个X86指令类似于"如果之前的条件值是false跳转那么",以避免两个分支预测(非常糟糕)
第二代码)最有可能总是执行简单的MOV(注册或很可能已经在缓存中的元素),这相对便宜(最多几个周期)
所以,我的意见是,除非处理器解码成微码指令可以做一些智能或X86指令存在以避免必要的分支预测,第二代码更快。
我理解这纯粹是理论上的问题,因为在实践中,这个分支可以使应用程序快0.000000002%或类似的东西。
我错过了什么吗?
编辑:我添加了一个循环,用于提供更多"体重"分支问题
EDIT2:问题是关于分支预测的英特尔架构(奔腾和更新的处理器)。
答案 0 :(得分:3)
使用 JMH 给出以下数字,其大小为 10 的 cardTypes 数组和整数增量作为逻辑(Java 15 / AMD 3950X / Windows 10):
Benchmark Mode Cnt Score Error Units
Benchmark.option1 thrpt 25 273369417.720 ± 1618952.179 ops/s
Benchmark.option2 thrpt 25 273415784.192 ± 852618.585 ops/s
“选项 2”的平均性能提高了约 0.017% (YMMV)。
另见:branch prediction、method dispatch、memory access、throughput and latency、garbage collection。
答案 1 :(得分:2)
代码具有相同的效果,但不会生成相同的字节代码或程序集(可能)。
这在性能方面有多大差异,目前尚不清楚,而且可能微不足道。
什么是远,更重要的是代码的清晰度。我看到了更多的错误和性能问题,因为在这样的简单情况下代码难以推理。
简而言之,对您来说最清楚和最简单的事情也可能足够快,或者最容易修复。
答案 2 :(得分:2)
不同的硬件对每个汇编指令都有不同的成本,而在现代硬件上,由于流水线和缓存的影响,甚至难以预测指令的成本。
在您的隔离示例中,if和if / else on pipelining和caches之间的区别并不明确。如果您运行该代码一次,则根本不会发现任何差异。在紧密的循环中反复运行它,if本身的性能将由a)支票的成本和b)支票结果的可预测性决定。换句话说,分支预测将成为主导因素,并且不会受到if或if / else代码块的影响。
关于分支预测效果的优秀讨论可以在这里阅读Why is it faster to process a sorted array than an unsorted array?(参见最高得分答案)。
答案 3 :(得分:0)
两个代码都具有相同的语义。
否两个代码都不同,
如果条件isFirst = false;
不匹配,首先将代码应用if (!isFirst)
设置为false。
每次将标志更改为false
,即使条件满足或不满足,也会使用第二个代码。
答案 4 :(得分:0)
if/else
构造中有两个分支:顶部的条件分支,以及else
部分末尾的if
部分周围的分支。 else
部分中没有分支,至少在任何中等程度上没有实现的编译器中都没有分支。
相反,你必须平衡总是执行isFirst = false;
行的费用。
在你提到的具体情况中,与方法调用的成本相比,它不太可能产生丝毫差异。
答案 5 :(得分:0)
假设您的代码段是for循环中的if块。 Hotspot具有展开for循环的能力,这包括采用常见的'循环的第一次迭代'检查并在循环外部内联它。从而避免了在循环的每次迭代中重新检查条件的成本。因此避免关注更快,if或else。
Oracle记录了此行为here