E os problemas de desempenho do try-catch?

"Sim, você olhou para este código fantasma e até fez um loop for try-catch, não sabe try-catchque há uma perda de desempenho?" O velho Chen apontou para o código na tela com seriedade:

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

Eu coloquei minha cabeça para olhar o código, "Velho Chen, como você acha que deveria ser mudado?"

“Claro que é para try-catchtrazer isso para fora!” Lao Chen deixou escapar sem nem mesmo pensar nisso.

"Você é estúpido? Deixando de lado o desempenho, o objetivo deste código é obviamente fazer com que um único erro de chamada dentro do loop não afete a execução do loop. Se você for para fora, a lógica de negócios mudará!"

O velho Chen coçou seu Mediterrâneo: "Parece ser o mesmo!"

"Olhando para trás, pegue todo o loop for e pegue dentro do loop, se não houver erro , o desempenho é realmente o mesmo." Tomei um gole de café e mencionei isso casualmente, pronto para mostrá-lo na frente de Lao Chen.

"O que você quer dizer?" Lao Chen olhou para mim um pouco confuso, " try-catchHá uma perda de desempenho, li as informações na Internet!"

Com certeza, Lao Chen mordeu a isca, abri a ideia sem dizer uma palavra e digitei o seguinte código em uma operação:

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ão é tão bom quanto mostrar código. Você viu, Lao Chen, vou try-catchtirá loop for e compará-lo com o loop for. Adivinha qual é a diferença entre os dois?"

"Corta, tenho certeza que tentar funciona bem, nem pense nisso, senão, vou lavar meu cabelo de cabeça para baixo!", prometeu o velho Chen.

Eu estava com preguiça de BB com ele e comecei o benchmark diretamente. Os resultados da corrida são os seguintes:

Percebe-se que o desempenho dos dois (quanto maior o número, melhor) é realmente semelhante:

  • arrependimento: 86.261(100359-14098) ~ 114.457(100359+14098)
  • tente por: 95,961(103216-7255) ~ 110,471(103216+7255)

Em seguida, ajustei o número de loops for para 1000 (o número de loops for em cenários gerais de negócios não será muitos) e o resultado é semelhante:

O velho Chen parecia perplexo: "E o impacto no desempenho? Por que ele desapareceu?"

我直接一个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,我们下篇见~

Acho que você gosta

Origin juejin.im/post/7204121228016091197
Recomendado
Clasificación