Executando verificação de segurança...
23

Mitos da otimização de código

Performance virou uma espécie de buzzword nos últimos tempos, onde muita gente gosta de falar sobre “truques” para deixar o código mais performático. Porém a maioria desses “truques” são completamente inúteis (não melhoram a performance) ou fazem uma diferença desprezível para a performance geral do software enquanto haveriam outras coisas que o desenvolvedor poderia fazer que realmente fariam uma diferença significativa na performance geral.

Este artigo foi escrito para quem não se interessa por truques, mandingas ou superstições e está interessado em realmente aprender como escrever softwares mais performáticos.

Mitos

Primeiramente acredito que seja importante falar sobre os erros que as pessoas aprendem sobre otimização de código, pois existe uma chance de que “sua xícara” esteja cheia de informações erradas que irão prejudicar o aprendizado sobre o assunto. Esvazie sua xícara primeiro.

O compilador já otimiza para mim

Embora seja verdade que compiladores modernos contém uma série de algoritmos para otimização de código e que, na gigantesca maioria das vezes, ele faz um bom trabalho, é falsa a ideia de que se o compilador já otimiza o código para você, então você não precisa se preocupar com a performance do código.

Acreditar nisso é equivalente a acreditar que você não precisa mais tomar banho porque a máquina de lavar chique que você comprou na semana passada já lava e seca as roupas para você.

O compilador realmente otimiza código, mas as otimizações que o compilador faz não são as mesmas otimizações que um programador faz manualmente. Então um não substitui o outro, os dois são igualmente necessários para a performance geral do programa.

Faça X e o código ficará mais rápido

Isso vale para qualquer afirmação que você tenha ouvido falar neste formato, como:

  • «Use if..else no lugar de switch..case e o código ficará mais rápido»
  • «Use for no lugar de recursão e o código ficará mais rápido»
  • «Use ponteiro ao invés de array e o código ficará mais rápido»
  • «Evite usar if e o código ficará mais rápido»
  • etc.

Estas afirmações não estão necessariamente erradas, mas o problema de acreditar nelas como se fosse uma verdade absoluta é que elas carregam um gigantesco DEPENDE implícito. O mito dessas superstições de “faça X e ficará mais rápido” provavelmente surgiu de algum desenvolvedor que sabia o que estava fazendo, fez uma alteração X no código para otimizar a performance e outro desenvolvedor viu aquilo e achou que se tratava de uma regra geral, uma espécie de magia para otimizar código. “O segredo para escrever código mais rápido que a NASA não quer que você saiba”, ou algo do tipo.

Então não, não adianta aplicar uma superstição no seu código achando que ele ficará mais rápido assim. Já vi vários casos de desenvolvedores que pioraram a performance do seu código enquanto aplicavam uma superstição para deixá-lo mais rápido.

Assembly é mais rápido

As pessoas acreditam muito no mito de que escrever código diretamente em assembly cria código mais performático do que código escrito em uma linguagem de alto nível como C. Mas escrever assembly não faz com que magicamente o código fique mais rápido. Isso depende exclusivamente da sua capacidade de escrever código mais performático do que o código assembly que o compilador gera. A gigantesca maioria dos desenvolvedores não conseguem fazer isso.

C é mais rápido

Muita gente até hoje ainda acredita no mito de que “C é a linguagem mais rápida” (ou algo parecido com isso) e por isso acham que seus programas serão “rápidos” só porque estão programando em C. Não é bem por aí, a linguagem não vai fazer milagre.

É o mesmo caso de escrever código em assembly, isso depende exclusivamente da sua capacidade de escrever um código performático em C. Não fique achando que só porque você está programando em C magicamente o programa tem boa performance. Nem ache que um programa escrito em outra linguagem seja necessariamente mais lento.

Falar de performance de uma linguagem de programação por si só já é uma coisa sem sentido, pois não tem lógica dizer que uma linguagem é mais rápida do que outra. Mas esse assunto é longo demais e não faz parte do escopo deste artigo explicar porque falar de “performance de linguagem” está tecnicamente errado.

Só complexidade de algoritmos importa

«…o resto é micro-otimização.»

Falso. Embora analisar a complexidade de algoritmos e se preocupar em escrever algoritmos mais eficientes de fato faça uma grande diferença na performance de um programa, é falsa a ideia de que isto é a única coisa que impacta significativamente a performance.

Este mito está intrinsecamente ligado ao mito de que os compiladores já otimizam o código e por isso “os programadores não precisam se preocupar em otimizar”. Pois a pessoa que acredita nesse mito acha que o programador só precisa se preocupar em escrever algoritmos mais eficientes e o compilador cuida do resto.

Performance não importa no começo

Falso. Muita gente acredita que no início do desenvolvimento de um software a performance não importa, que tudo bem escrever o código “de qualquer jeito” pois a performance só vai ser importante depois de meses ou anos do lançamento do software.

Embora a afirmação não esteja totalmente errada, é um grande erro acreditar que você só precisa se preocupar com a performance do software “depois”. Existem várias preocupações com a performance do sistema que precisam (reforço: precisam, é necessário!) serem levadas em consideração desde o começo do desenvolvimento e até mesmo antes disso (na fase de planejamento/design).

Embora otimização de códigos específicos (como uma função) possam de fato serem deixados para depois, decisões que envolvem a arquitetura do software precisam levar em consideração a performance desde o começo. Pois se não levarem em consideração, não é um problema que pode ser corrigido “depois”. Você teria que mudar a arquitetura do software, o que não pode ser resolvido simplesmente otimizando “aqui” ou “ali” ou refatorando “isso” ou “aquilo”.

Ou seja, performance não diz respeito somente a pedaços de códigos (como funções) mas também diz respeito ao software como um todo. As questões de performance que dizem respeito ao software como um todo não podem ser deixadas para depois e devem ser pensadas desde o começo.

Comparação de hello worlds ou loops

(ou outros pedaços de código que não fazem nada de verdade)

É mito achar que comparar “hello worlds” entre várias linguagens de programação diz alguma coisa em relação a “qualidade” da linguagem. Isso vale também para quando comparam medições de performance com pequenos loops escritos em várias linguagens diferentes e criam um ranque inútil de “linguagens mais rápidas”.

Não é assim que se mede a performance de um software, isso é erro de principiante.

Comparar o tamanho de softwares “Hello Worlds” em várias linguagens diferentes não diz absolutamente nada sobre a qualidade da linguagem de programação ou do compilador. Isso só diz o tamanho das bibliotecas estáticas que foram linkadas ao executável.

Comparar o benchmark de código com loops feito especificamente para fazer o benchmark usando várias linguagens diferentes não diz nada sobre a qualidade da linguagem de programação ou do compilador. Benchmark de verdade deve ser feito com código de verdade, não com código feito para rodar no benchmark só para fazer um rank sem lógica de linguagens mais rápidas.

E um aviso importante: A performance de um trecho de código específico (como uma função) não reflete a performance de um sistema real como um todo. Ledo engano pensar que só porque um código X é mais rápido compilado com a linguagem A do que com a linguagem B, isso significa que sistemas escritos em A são mais rápidos do que sistemas escritos em B.

Performance de software é muito mais complexo do que isso. Comparar a performance de pequenos trechos de código nunca, em hipótese alguma, é uma boa medição para determinar a performance de um sistema completo.

Entendendo performance

Agora (eu espero) os mitos mencionados acima já foram entendidos como erros e que nada daquilo é de fato “entender de performance”, “ser programador raiz” ou qualquer coisa parecida.

Para ser capaz de escrever softwares performáticos é necessário, antes de mais nada, entender o que é performance: A performance de um software é basicamente o quão bem ele usa os recursos do hardware. Quanto melhor um software se aproveita dos recursos do hardware, quanto menor é o “desperdício” desses recursos, mais performático é o software.

Esses recursos podem ser vários, mas os dois principais são: Memória (quanta RAM o seu software usa) e CPU (quanto processamento da CPU o seu software consome).

Tendo isto em mente, fica claro que é necessário entender como, quando e o quanto de recursos do hardware o seu código está usando. Sem ter esta visão, tentar escrever código performático é uma tarefa inútil.

Mas além do “óbvio” acima, também é importante entender quando o seu software fica ocioso, isto é, “parado” esperando alguma coisa acontecer. Pois o tempo ocioso afeta o tempo de execução geral do software. Identificar quando essas “paradas” ocorrem e como evitá-las/diminuir o tempo de espera, também é uma habilidade necessária para ser capaz de escrever softwares que terão menor tempo de execução no geral.

Otimização de código

Otimizar código é o ato de escrever código mais performático. Como você pode reparar “mais performático” requer um ponto de referência, pois é relativo. Não dá para otimizar um código que não existe, é uma afirmação que nem faz sentido. Então tire da cabeça que você irá escrever um código “otimizado” logo na primeira versão do código, pois não tem lógica pensar assim.

Logo, é importante compreender que otimizar código não é uma tarefa primária no desenvolvimento de software. Primeiro você escreve o código e depois, com a primeira versão do código já escrita, você otimiza ele.

Obs.: Isso não significa que performance deve ser ignorada no início do desenvolvimento do software. Como já foi corrigido em um dos mitos mencionados neste artigo, pensar assim é um erro.

Entendido isto, você não pode dizer que “otimizou” um código sem ter evidências de que realmente o novo código é mais performático do que o código anterior. É importante colocar isso na cabeça para não cair em superstições e achar que está escrevendo código “otimizado” quando não está. Tendo as evidências, não há o que se discutir. Não precisa depender de “opinião”, é um fato.

E para obter essas evidências se faz benchmark tanto do código antigo quanto do novo.

Benchmark

Fazer benchmark é medir o consumo de recursos (*geralmente só RAM e CPU) de um determinado trecho de código (como uma função, por exemplo). Tendo a medição, você consegue comparar a performance de duas versões do código e dizer qual delas é mais performática.

Não cabe ao escopo do artigo explicar como fazer benchmark, mas que fique avisado que a maioria das pessoas que eu vejo tentando fazer benchmark fazem do jeito errado. Portanto prefira usar soluções prontas para fazer benchmark caso não saiba o que está fazendo. Há grandes chances de já existir ferramentas/bibliotecas de benchmark nas linguagens que você usa.

*Obs.: Exceto em trechos de código que consumam outros recursos de hardware no qual você está interessado em otimizar, como: VRAM, GPU, I/O, rede etc.

Profiling

Profiling é essencialmente o mapeamento do consumo de recursos ao longo da execução de um software. Geralmente ferramentas de profiling medem o tempo de execução de funções, uso de memória e outros detalhes que são úteis para mapear quais partes do código são mais críticas para a performance do programa e quais são mais lentas e/ou consomem mais memória.

Provavelmente já existem ferramentas para profiling nas linguagens que você usa, então use-as para ter dados e fazer otimização de código onde realmente faz diferença para a performance como um todo do software.

É comum que desenvolvedores joguem tempo fora tentando fazer otimizações de códigos que não mudam em absolutamente nada a performance do software. Muito mais comum do que você está pensando.

Fazer profiling é uma maneira de ter evidências de que trechos X ou Y do software precisam de otimização e que esta otimização irá realmente fazer diferença na performance do software.

O que REALMENTE faz diferença na performance

Até então você já compreendeu erros comuns que as pessoas cometem quando o assunto é performance e já compreendeu o que é performance, o que se deve fazer para otimizar código e como obter dados para fazer otimizações que realmente fazem a diferença na performance de um software.

Mas ainda não sabe como de fato, na prática, você pode fazer softwares mais performáticos. Esta seção tem o intuito de dar dicas e explicações do que você pode fazer nos seus softwares que realmente impactam positivamente a performance de um software, sem superstições ou mandingas. E agora que você já entende sobre como ter evidências de que a performance de um software realmente melhorou (ou não), então você não precisa nem deve “acreditar” em mim. Faça o teste, meça e veja se é verdade ou não que fazer essas coisas realmente melhoram a performance do código.

CONTINUA...

Este artigo é muito grande e o seu conteúdo completo não cabe aqui em uma postagem do TabNews. Para ler a continuação do artigo e aprender como escrever códigos mais performáticos, você pode:

Escolha o que achar melhor.

Carregando publicação patrocinada...
3

Muitos desses mitos e superstições vem de uma época remota da computação.
Naquela época nós dávamos nomes as variáveis como A, B e C para economizar memória.
O compilador também não fazia nenhuma otimização.

Naquela época esses mitos funcionavam, mas hoje precisam ser descartados.

1

Realmente. Esta parte do tamanho dos nomes das variáveis é um bom ponto. Até recentemente eu ainda vi gente repetindo isto, que dar nomes curtos às variáveis é melhor para a "performance".

Hehe, o pessoal fica repetindo coisas do passado sem levar em consideração que computação evolui muito rápido.

1

Bacana!

As técnicas de otimização também são diferentes para diferentes cenários.

Se você está investigando baixa performance de um endpoint na sua API, os problemas são X.

Se você está investigando um problema de performance na renderização do seu app React, os problemas são Y.

1

Queria ver o comentario e a aula que o Julio Neves professor de shell daria pra esse post aqui eheheeh, certamente ele provaria com codigo, com loops mostraria tempos etc, o cara é especialista nisso!!
Por experiencia propria, sempre procuro criar programas enxutos, ou simplesmente faço funcionar, depois otimizo o codigo, ja tive varios casos de sucesso como:

  • Em arduino, esp, otimizar o codigo pra ser mais rapido e mais leve, evita travamentos!
  • criação de um "robo" compra e venda de cripto em BASH que demorava uns 10 minitos para tomar "decisão", otimizei pra 3 minutos, e depois consegui pra 1 minuto.
  • criação de videos autonomos, copilação do video em FFMPEG tava demorando demais, tive um trabalhão para gerar um comando só, e depois tive que desmembrar os comandos, e gerar comandos executados em paralelo, e esse paralelismo só é limitado pelo hardware, nesse caso passei a ter 30x mais rapido!
  • Recentemente agora criando jogos eheheeh, percebo algumas limitações em mapas abertos, mapas gigantes variaveis que vão do -4096 a 4096 tonando muito limitado, e pesado o jogo, então uso apenas uns 50 dessas unidades pra renderizar apenas o que é mostrado ehehehe, o jogo fora da tela ta todo cagado, ate que vc chegue ate la e ta tudo perfeito!

Sempre busco criar minhas libs, otimizando e usando so o que preciso, por exemplo em vez de usar uma lib completa de algo uso um simples regex, enfim, acaba que isso performa mais, vc dorme tranquilo e sabe tudo que ta dentro do codigo e como tudo funciona, e nao se assusta com nenhuma atualização de lib que vc mau sabe o que tem la dentro! ou seja meus programs dificilmente quebram, dificilmente trava. e quanto algo acontece é só e la e corrigir!

1

Muita gente cai na ilusão de "truques mágicos" para otimizar código, mas a verdade é que performance exige análise real, não superstição. Benchmark e profiling são essenciais para saber o que realmente faz diferença. Antes de sair aplicando dicas aleatórias, meça e teste!

1

Verdade. Não sei porque mas isso ficou bem mais comum nos últimos anos. Deve ter tido influência de alguém "famoso" ou algo assim. Não acho que seja coincidência que do nada começaram a espalhar este tipo de bobagem com mais frequência nas comunidades de desenvolvimento.