考虑到“if”语句和异常的长期性能成本

6

我一直认为使用“if”语句比捕获异常更好(从性能角度来看)。例如,执行以下操作:

User u = Users.getUser("Michael Jordan");
if(u!=null)
   System.out.println(u.getAge());

对比。

User u = Users.getUser("Michael Jordan");
try{
   System.out.println(u.getAge());
}catch(Exception e){
   //Do something with the exception
}

如果我们进行基准测试,很明显第一段代码比第二段要快。这是我一直以来的想法。但是,昨天有个人告诉我这样的话:
“你有没有考虑过,当你的程序被执行成千上万次时会发生什么?每次执行到你的‘if’语句时,都会有一点(虽然很小,但还是有)性能损耗。但是使用异常就不会出现这种情况,因为它永远不会发生。”
换句话说:执行千万次“if”语句与捕获一个异常相比。
我认为这个观点有道理,但没有任何证据。
你能帮帮我吗?
谢谢!

2
那个人告诉你的有问题。说“假设执行了10亿次1纳秒操作-这很多!”是错误的。只有当它占整个执行时间的显着百分比时,才算是很多。你必须看整个情况,不能孤立地看待它。 - Mike Dunlavey
真的。好观点。我没有考虑过。 - santiagobasulto
4个回答

9

不会。一旦JIT启动,就不会了。告诉他阅读关于跟踪缓存的内容。

动态跟踪(“跟踪路径”)仅包含实际使用其结果的指令,并消除后续取出的分支指令(因为它们未执行);动态跟踪可以是多个基本块的串联。这允许处理器的指令获取单元获取多个基本块,而不必担心执行流中的分支。

基本上,如果循环体中每次都采用相同的分支,则该体最终成为跟踪缓存中的单个跟踪。处理器将不会承担获取额外分支指令的成本(除非将基本块推到超出跟踪缓存可存储限制的范围,这不太可能),并且在开始执行以下指令之前无需等待测试结果。


1
谢谢Mike!那就是我在寻找的证明。真的很棒! - santiagobasulto

9

绝对不要为了性能而牺牲代码质量,除非你已经证明这是必要的。我非常怀疑if()语句的性能会成为程序的瓶颈。如果确实出现了这种情况,你应该用C重新编写它。在Java领域中,99%的时间瓶颈是I/O——磁盘和/或网络。


完全同意!但这只是一个问题。从来没有想过。我不打算这样做! - santiagobasulto

2
除了机器异常之外,你捕获的任何异常都是在某种if条件语句之前发生的。即使是NullPointerException也是在JVM中的if(something == null)后抛出的。不要担心if语句的性能。也不要担心try/catch的性能,因为错误发生的频率应该比成功执行少得多。我认为你不需要优化错误抛出的速度。 :-)

很好的观点,Dave!有太多的东西在引擎盖下面,不能做出那种假设。我没有想过这个。 - santiagobasulto

1

你没有证据,因为你没有案例。如果你有一段代码是瓶颈,可以通过消除一个if语句来优化,因为条件的一侧非常罕见,那么这肯定是一个有趣的抽象问题。但在抽象层面上,使用异常来实现这个目的会使代码更难阅读和维护,所以不应该在没有真正的实际问题的情况下这样做。在现实世界中,它可能会50%的时间抛出异常。只有在真实场景中才能知道。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接