"Otimização prematura é a raiz de todo mal" é algo que quase todos nós ouvimos / lemos. O que estou curioso é que tipo de otimização não é prematuro, ou seja, em todas as etapas do desenvolvimento de software (design de alto nível, design detalhado, implementação de alto nível, implementação detalhada etc.) qual é o grau de otimização que podemos considerar sem que ela passe para o lado escuro.
optimization
Gaurav
fonte
fonte
Respostas:
Quando você está baseando-se na experiência? Não é mau. "Toda vez que fizemos o X, sofremos um impacto brutal no desempenho. Vamos planejar otimizar ou evitar o X totalmente dessa vez."
Quando é relativamente indolor? Não é mau. "Implementar isso como Foo ou Bar exigirá muito trabalho, mas, em teoria, o Bar deve ser muito mais eficiente. Vamos barrar".
Quando você está evitando algoritmos de baixa qualidade, que escalam terrivelmente? Não é mau. "Nosso líder técnico diz que nosso algoritmo de seleção de caminho proposto é executado em tempo fatorial; não tenho certeza do que isso significa, mas ela sugere que cometamos seppuku por considerá-lo. Vamos considerar outra coisa."
O mal vem de gastar muito tempo e energia resolvendo problemas que você não sabe que realmente existem. Quando os problemas existem definitivamente, ou quando os psudo-problemas fantasmas podem ser resolvidos de maneira barata, o mal desaparece.
Steve314 e Matthieu M. levantam pontos nos comentários que devem ser considerados. Basicamente, algumas variedades de otimizações "indolores" simplesmente não valem a pena porque a atualização trivial de desempenho que eles oferecem não vale a ofuscação do código, estão duplicando aprimoramentos que o compilador já está executando, ou ambos. Veja os comentários para alguns bons exemplos de não-melhorias muito inteligentes pela metade.
fonte
i
não tiver sinal,i / 2
pode ser substituído pori >> 1
. É mais rápido. Mas também é mais enigmático (nem todos verão o efeito, mesmo aqueles que o fazem podem perder tempo). Mas o pior de tudo é que o compilador fará isso de qualquer maneira, então por que ofuscar o código-fonte;)?i/2
é realmente um ponto quente e que (inacreditável, mas vamos supor) oi>>1
torna mais rápido, faça-o e faça um comentário de que esse perfil mostrou que é mais rápido. Se isso é realmente necessário em qualquer lugar (o que eu duvido, já que, como Matthieu disse, os compiladores devem ser inteligentes o suficiente para fazer isso), os iniciantes aprenderão algo, se não for (o que é provável), por que você deseja conectar suas cabeças com folclore desnecessário?O código do aplicativo deve ser tão bom quanto necessário, mas o código da biblioteca deve ser o melhor possível, pois você nunca sabe como sua biblioteca será usada. Portanto, quando você estiver escrevendo código de biblioteca, ele precisa ser bom em todos os aspectos, seja desempenho, robustez ou qualquer outra categoria.
Além disso, você precisa pensar em desempenho ao projetar seu aplicativo e ao escolher algoritmos . Se não foi projetado para ter desempenho, nenhum grau de hackeamento pode ter desempenho posterior e nenhuma micro otimização superará um algoritmo superior.
fonte
O tipo resultante de problemas conhecidos.
fonte
É difícil dizer o que é bom e mau. Quem tem esse direito? Se olharmos para a natureza, parece que estamos programados para a sobrevivência com uma ampla definição de "sobrevivência", que inclui a transmissão de nossos genes para a prole.
Então eu diria, pelo menos de acordo com nossas funções e programação básicas, que a otimização não é má quando está alinhada com o objetivo da reprodução. Para os caras, existem as loiras, morenas, ruivas, muitas adoráveis. Para as meninas, existem homens, e alguns deles parecem estar bem.
Talvez devêssemos otimizar esse objetivo, e aí ajuda o uso de um criador de perfil. O criador de perfil permitirá que você priorize suas otimizações e tempo com mais eficiência, além de fornecer informações detalhadas sobre pontos de acesso e por que eles ocorrem. Isso lhe dará mais tempo livre gasto para a reprodução e sua busca.
fonte
A cotação completa define quando a otimização não é prematura:
Você pode identificar código crítico de várias maneiras: estruturas ou algoritmos de dados críticos (por exemplo, usados intensamente ou o "núcleo" do projeto) podem oferecer grandes otimizações, muitas otimizações menores são identificadas por meio de criadores de perfil e assim por diante.
fonte
Você sempre deve escolher uma solução "suficientemente boa" em todos os casos, com base em suas experiências.
O ditado de otimização refere-se à escrita "código mais complexo do que 'bom o suficiente' para torná-lo mais rápido" antes de realmente saber que é necessário, tornando o código mais complexo do que o necessário. Complexidade é o que dificulta as coisas, de modo que não é uma coisa boa.
Isso significa que você não deve escolher uma rotina de classificação super complexa "pode classificar arquivos de 100 Gb trocando de forma transparente para o disco" quando uma classificação simples ocorrer, mas você também deve fazer uma boa escolha para a classificação simples. Escolhendo cegamente a Classificação por bolha ou "escolha todas as entradas aleatoriamente e veja se estão em ordem. Repita". raramente é bom.
fonte
Minha regra geral: se você não tiver certeza de que precisará da otimização, presuma que não. Mas lembre-se de quando você precisa otimizar. Existem alguns problemas que você pode conhecer antecipadamente. Isso geralmente envolve a escolha de bons algoritmos e estruturas de dados. Por exemplo, se você precisar verificar a associação em uma coleção, pode ter certeza de que precisará de algum tipo de estrutura de dados definida.
fonte
Na minha experiência, na fase de implementação detalhada, a resposta está na criação de perfil do código. É importante saber o que precisa ser mais rápido e o que é aceitavelmente rápido.
Também é importante saber onde está exatamente o gargalo de desempenho - otimizar uma parte do código que leva apenas 5% do tempo total para executar não é bom.
As etapas 2 e 3 descrevem a otimização não prematura:
fonte
Não é otimização ao escolher coisas difíceis de mudar, por exemplo: plataforma de hardware.
A escolha de estruturas de dados é um bom exemplo - essencial para atender aos requisitos funcionais e não funcionais (desempenho). Não é facilmente alterado e, no entanto, direcionará todo o resto do seu aplicativo. Suas estruturas de dados alteram quais algoritmos estão disponíveis etc.
fonte
Eu só conheço uma maneira de responder a essa pergunta, e é obter experiência no ajuste de desempenho. Isso significa - escreva programas e, depois de escritos, encontre acelerações neles e faça-o iterativamente. Aqui está um exemplo.
Aqui está o erro que a maioria das pessoas comete: Eles tentam otimizar o programa antes de executá-lo. Se eles fizeram um curso de programação (de um professor que na verdade não tem muita experiência prática), eles terão grandes óculos de cor O e pensarão que é disso que se trata . É tudo o mesmo problema, otimização prévia. **
Alguém disse: Primeiro, faça certo, depois rápido. Eles estavam certos.
Mas agora, para o kicker: se você já fez isso algumas vezes, reconhece as coisas tolas que fez anteriormente que causam problemas de velocidade, e evita-as instintivamente. (Coisas como tornar sua estrutura de classe muito pesada, sobrecarregar-se de notificações, tamanho confuso de chamadas de função com seu custo de tempo, a lista continua indefinidamente ...) Você as evita instintivamente, mas adivinhe o que parece ser para os menos- experiente: otimização prematura!
Então esses debates bobos continuam :)
** Outra coisa que eles dizem é que você não precisa mais se preocupar com isso, porque os compiladores são muito bons e as máquinas são tão rápidas hoje em dia. (KIWI - Kill It With Iron.) Não há acelerações exponenciais de hardware ou sistema (feitas por engenheiros muito inteligentes) que podem compensar lentidão exponencial de software (feita por programadores que pensam assim).
fonte
Quando os requisitos ou o mercado solicitam especificamente.
Por exemplo, o desempenho é um requisito na maioria dos aplicativos financeiros, porque a baixa latência é crucial. Dependendo da natureza do instrumento comercializado, a otimização pode passar do uso de algoritmos sem travamento em uma linguagem de alto nível até o uso de uma linguagem de baixo nível e até o extremo - implementar os algoritmos de correspondência de ordem no próprio hardware (usando FPGA por exemplo )
Outro exemplo seria alguns tipos de dispositivos incorporados. Tomemos, por exemplo, o freio ABS; Em primeiro lugar, há a segurança; quando você bate no freio, o carro deve desacelerar. Mas também há desempenho, você não gostaria de atrasos quando acertar o intervalo.
fonte
A maioria das pessoas chamaria a otimização prematura, se você estiver otimizando algo que não está resultando em uma "falha leve" (funciona, mas ainda é inútil) do sistema devido ao desempenho.
Exemplos do mundo real.
Se minha classificação de bolha demorar 20ms para ser executada, otimizá-la para 1ms quicksort não melhorará o utilitário geral de maneira significativa, apesar de haver um aumento de desempenho de 2000%.
Se uma página da web leva 20s para carregar e a diminuímos para 1s, isso pode aumentar o utilitário do site de 0 para o infinito próximo. Basicamente, algo que foi quebrado por ser muito lento agora é útil.
fonte
Que tipo de otimização não é prematura?
Uma otimização que corrige um problema de desempenho conhecido com seu aplicativo ou uma otimização que permite que seu aplicativo atenda a critérios de aceitação bem definidos.
Tendo sido identificado, deve-se levar algum tempo para estabelecer a correção e o benefício de desempenho deve ser medido.
(ou seja, não é - "Eu acho que esse pedaço do código pode parecer lento, mudarei o X para usar Y e será mais rápido").
Eu encontrei muitas "otimizações" prematuras que acabaram tornando o código mais lento - neste caso, estou considerando prematuro significar 'não pensado'. O desempenho deve ser comparado antes e depois da otimização e apenas o código que realmente melhora o desempenho mantido.
fonte
Verdadeiro. Infelizmente, é também uma das citações de programação mais mal utilizadas (maliciosamente) de todos os tempos. Desde que Donald Knuth cunhou o meme, vale a pena adicionar algum contexto original da citação:
Observe que Knuth falou especificamente sobre velocidade de execução em tempo de execução .
Além disso, ele escreveu o artigo em 1974, quando qualquer recurso de máquina que apresentasse correlação premium e negativa entre velocidade de execução e capacidade de manutenção do programa (maior velocidade - menos manutenção) provavelmente fosse mais forte do que agora.
OK, para responder sua pergunta, de acordo com Donald Knuth, a otimização NÃO é prematura se corrigir um sério gargalo de desempenho que foi identificado (idealmente medido e identificado durante a criação de perfil).
Como eu disse antes, "otimização prematura" é um dos memes mais mal-intencionados, então a resposta não será completa sem alguns exemplos de coisas que não são otimizações prematuras, mas que às vezes são descartadas da seguinte forma:
Além disso, nem sequer estão relacionados à velocidade de execução do tempo de execução:
projeto adiantado pensativo
digitação estática (!)
etc. / quaisquer formas de esforço mental
fonte