Qu'en est-il des problèmes de performances try-catch ?

"Oui, vous avez regardé ce code fantôme, et même fait une boucle for try-catch, ne savez-vous pas try-catchqu'il y a une perte de performance ?" Le vieux Chen a pointé sérieusement le code à l'écran :

 for (int i = 0; i < 5000; i++) {
     try {
         dosth
     } catch (Exception e) {
         e.printStackTrace();
     }
 }
复制代码

J'ai poussé ma tête pour regarder le code, "Old Chen, comment pensez-vous qu'il devrait être changé?"

"Bien sûr, c'est try-catchpour le sortir !", lâche Lao Chen sans même y penser.

"Êtes-vous stupide ? Laissant de côté les performances, le but de ce code est évidemment de faire en sorte qu'une seule erreur d'appel à l'intérieur de la boucle n'affecte pas le fonctionnement de la boucle. Si vous sortez, la logique métier changera !"

Le vieux Chen a gratté sa Méditerranée, "Il semble que ce soit la même chose!"

"En regardant en arrière, attrapez l'intégralité de la boucle for et attrapez à l'intérieur de la boucle, s'il n'y a pas d'erreur , la performance est en fait la même." J'ai pris une gorgée de café et l'ai mentionné avec désinvolture, prêt à le montrer devant Lao Chen.

"Qu'est-ce que tu veux dire?" Lao Chen m'a regardé un peu confus, " try-catchIl y a une perte de performance, j'ai lu les informations sur Internet!"

Effectivement, Lao Chen a pris l'appât, j'ai ouvert l'idée sans dire un mot, et j'ai tapé le code suivant en une seule opération :

public class TryCatchTest {

    @Benchmark
    public void tryfor(Blackhole blackhole) {
        try {
            for (int i = 0; i < 5000; i++) {
                blackhole.consume(i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Benchmark
    public void fortry(Blackhole blackhole) {
        for (int i = 0; i < 5000; i++) {
            try {
                blackhole.consume(i);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
复制代码

"BB n'est pas aussi bon que le code d'affichage. Avez-vous vu cela, Lao Chen, je vais le try-catchsortir boucle for et le comparer avec la boucle for. Devinez quelle est la différence entre les deux?"

"Coupez, je suis sûr que tryfor fonctionne bien, n'y pensez même pas, sinon, je vais me laver les cheveux à l'envers!" a juré le vieux Chen.

J'étais trop paresseux pour BB avec lui et j'ai commencé le benchmark directement. Les résultats de la course sont les suivants :

On peut voir que les performances des deux (plus le nombre est grand, mieux c'est) sont en fait similaires :

  • regret : 86 261(100359-14098) ~ 114 457(100359+14098)
  • essai : 95 961(103216-7255) ~ 110 471(103216+7255)

J'ai ensuite ajusté le nombre de boucles for à 1000 (le nombre de boucles for dans les scénarios commerciaux généraux ne sera pas élevé), et le résultat est similaire :

Old Chen avait l'air abasourdi: "Qu'en est-il de l'impact sur les performances? Pourquoi est-il parti?"

我直接一个javap,让老陈看看,其实两个实现在字节码层面没啥区别:

tryfor 的字节码

异常表记录的是 0 - 20 行,如果这些行里面的代码出现问题,直接跳到 23 行处理

fortry 的字节码

差别也就是异常表的范围小点,包的是 9-14 行,其它跟 tryfor 都差不多。

所以从字节码层面来看,没抛错两者的执行效率其实没啥差别。

“那为什么网上流传着try-catch会有性能问题的说法啊?”老陈觉得非常奇怪。

这个说法确实有,在《Effective Java》这本书里就提到了 try-catch 性能问题:

并且还有下面一段话:

正所谓听话不能听一半,以前读书时候最怕的就是一知半解,因为完全理解选择题能选对,完全不懂蒙可能蒙对,一知半解必定选到错误的选项!

《Effective Java》书中说的其实是不要用 try-catch 来代替正常的代码,书中的举例了正常的 for 循环肯定这样实现:

但有个卧龙偏偏不这样实现,要通过 try-catch 拐着弯来实现循环:

这操作我只能说有点逆天,这两个实现的对比就有性能损耗了

我们直接再跑下有try-catch 的代码和没 try-catch的 for 循环区别,代码如下:

结果如下:

+-差不多,直接看前面的分数对比,没有 try-catch 的性能确实好些,这也和书中说的 try-catch 会影响 JVM 一些特定的优化说法吻合,但是具体没有说影响哪些优化,我猜测可能是指令重排之类的。

好了,我再总结下有关 try-catch 性能问题说法:

  1. try-catch 相比较没 try-catch,确实有一定的性能影响,但是旨在不推荐我们用 try-catch 来代替正常能不用 try-catch 的实现,而不是不让用 try-catch
  2. for循环内用 try-catch 和用 try-catch 包裹整个 for 循环性能差不多,但是其实两者本质上是业务处理方式的不同,跟性能扯不上关系,关键看你的业务流程处理。
  3. 虽然知道try-catch会有性能影响,但是业务上不需要避讳其使用,业务实现优先(只要不是书中举例的那种逆天代码就行),非特殊情况下性能都是其次,有意识地避免大范围的try-catch,只 catch 需要的部分即可(没把握全 catch 也行,代码安全执行第一)。

“好了,老陈你懂了没?”

“行啊yes,BB是一套一套的,走请你喝燕麦拿铁!” 老陈一把拉起我,我直接一个挣脱,“少来,我刚喝过咖啡,你那个倒立洗头,赶紧的!”我立马意识到老陈想岔开话题。

“洗洗洗,我们先喝个咖啡,晚上回去给你洗!”

晚上22点,老陈发来一张图片:

你别说,这头发至少比三毛多。

我是yes,我们下篇见~

Guess you like

Origin juejin.im/post/7204121228016091197