AFu*_*sco 2 java performance jvm
我正在编写一个算法,其中效率非常重要。有时我也想通过调用一些“回调”函数来跟踪算法行为。假设我的代码如下所示:
public float myAlgorithm(AlgorithmTracker tracker) {
while (something) { // millions of iterations
doStuff();
if (tracker != null) tracker.incrementIterationCount(); // <--- How to run the if only once?
doOtherStaff();
}
}
Run Code Online (Sandbox Code Playgroud)
如何防止执行 if 语句一百万次?编译器是否看到tracker从未重新分配?如果它在第一次检查时为空,它将始终为空。如果不是,则永远不会。
理想情况下,我想告诉编译器以这种方式构建我的代码,以便如果tracker为 null(在运行时),它将以与以下相同的性能运行
while (something) { // millions of iterations
doStuff();
doOtherStaff();
}
Run Code Online (Sandbox Code Playgroud)
我想到了两个解决方案:
我可以编写两个版本的 myAlgorithm,一个有调用,一个没有调用,但这会导致大量代码重复。
我可以将 AlgorithmTracker 提取到一个界面并创建一个带有空函数的假空跟踪器。不过,我不知道编译器是否会优化调用。
对于大多数 CPU 架构,您不必担心要应用的优化,因为该特定优化是大多数现代 CPU 的一部分。它被称为分支预测,当前的 CPU 非常擅长这一点。
平均而言,CPU 执行的每 6 条指令都是一个分支,如果对于每个分支 CPU 都必须等待并评估分支条件,则会使执行速度变慢。
因此,当面对分支时,在不评估分支条件的情况下,CPU 开始执行(推测执行)它认为很可能是正确的路径,并且在稍后阶段,当分支条件的结果可用时,CPU 会检查它是否正确执行正确的路径。
如果 CPU 选择的路径与分支条件的结果一致,则 CPU 知道它正在执行正确的路径,因此它会保持 100% 的速度,否则它将不得不刷新所有它推测执行的指令并开始正确的路径。
进入 CPU 的分支预测子系统。在最基本的形式中,它将存储有关分支过去行为的信息,例如,如果某个分支在一段时间内未被选中,那么它现在很可能不会被选中。这是一个简单的解释,真正的分支预测器将非常复杂。
鉴于分支预测器的核心只是模式匹配机器,如果您的分支显示出可预测的模式,那么您可以放心,分支预测器会得到正确的结果。但是如果你的分支根本没有显示任何模式,那么分支预测器就不会帮助你,最糟糕的是它会因为所有错误的预测而妨碍你的代码执行。
在你的情况下,分支控制变量的值永远不会改变,所以分支要么在循环的每次迭代中被选中,要么永远不会被选中。这清楚地显示了一种模式,即使是最基本的分支预测器也可以识别。这意味着您的代码实际上会像条件不存在一样执行,因为在前几次迭代之后,分支预测器将能够以 100% 的准确度选择路径。
要了解更多信息,请阅读这篇很棒的文章
有趣的事实:这种特殊的优化是 CPU 漏洞(如幽灵和崩溃)的原因