Enquanto construo aplicativos, me pergunto constantemente se essa é a melhor maneira de executar ou implementar uma certa funcionalidade. Frequentemente, postarei perguntas no stackoverflow ou em outro fórum que deseje feedback apenas para receber comentários sobre como "não colocar a carroça na frente dos bois" em relação ao desempenho. A maioria dos programadores realmente não pensa em desempenho até que o aplicativo seja concluído ou o desempenho é absolutamente inaceitável? Quero dizer, eu entendo que os ambientes de desenvolvimento diferem dos ambientes de produção e que você não deve confiar completamente nos resultados do seu laptop de desenvolvimento ... mas existem práticas e técnicas que produzem melhor desempenho do que outras.
É uma má prática considerar o desempenho durante todo o processo de desenvolvimento? Devo adiar essas considerações até que o desempenho seja realmente prejudicial?
Atualizar
Só para esclarecer, estou falando da situação em que você está pensando ou está prestes a trabalhar em alguma funcionalidade. Você sabe que existem várias maneiras de implementá-lo, mas não tem certeza de quão bem cada implementação será dimensionada. Também pode haver várias técnicas que você nem conhece. Em pequena escala, qualquer uma das abordagens provavelmente seria adequada, mas em uma escala maior algumas se manterão e outras não. Muitas vezes, quando peço opiniões ou orientação, a resposta é: se preocupe com isso mais tarde ...
fonte
Respostas:
O adiamento das considerações de desempenho às vezes se baseia em um aplicativo incorreto da frase:
Se você ler a citação completa, o que Knuth estava tentando dizer é que as micro otimizações aplicadas durante o desenvolvimento sem criação de perfil são geralmente desaconselháveis, porque levam a um código menos sustentável, sem necessariamente obter benefícios substanciais de desempenho.
Mas isso não significa que você não deve considerar o desempenho até que o aplicativo esteja quase pronto. Se você fizer isso, poderá achar que o desempenho é inadequado, sua arquitetura de design não suporta melhor desempenho e é necessário recomeçar.
Há várias coisas que você pode fazer durante o desenvolvimento para obter um bom desempenho, sem otimizações esotéricas (e prematuras):
Se você fizer essas coisas, descobrirá que qualquer otimização de desempenho que precise ocorrer ficará confinada a uma pequena parte do seu código. A criação de perfil identificará esse código e permitirá que você concentre suas melhorias de desempenho onde elas serão mais benéficas, sem sacrificar a capacidade de manutenção.
fonte
Aqui está o que NÃO PENSAR:
++i
mais rápido quei++
?switch
mais rápido queif
?inline
minhas funções?Aqui está o que pensar:
Em relação ao último ponto, na minha experiência, é melhor projetar a estrutura de dados para que, se ela não for normalizada, possa tolerar inconsistência temporária, que pode ser resolvida posteriormente por algum tipo de varredura periódica. Um dos principais fatores de desempenho é quando as notificações acionam notificações adicionais, que acionam ainda mais, a uma extensão que você nunca imaginaria antes. E, muitas vezes, é um esforço desperdiçado devido a alterações de cancelamento automático.
Se você fez tudo isso, tem um design limpo. Periodicamente, à medida que você o desenvolve, faça um perfil. ( Pausa aleatória é o método em que confio.) Então, se você puder ver que o desempenho seria aprimorado, trazendo um algoritmo mais sofisticado, faça isso de qualquer maneira.
fonte
Não, você deve pensar em desempenho (especialmente no design de bancos de dados) desde o início. Houve muitos danos à nossa indústria por pessoas que pensam que qualquer otimização é otimização prematura. A citação tinha como objetivo original impedir que as pessoas olhassem para micro-otimizações antes que um problema ocorresse. Não se destinava a não fazer nenhuma otimização. Em um banco de dados, por exemplo, existem muitas técnicas conhecidas que apresentam desempenho ruim. Evitar isso, no design, faz parte do que você precisa fazer. É muito difícil refatorar um banco de dados com 100.000.000 de registros, porque ele foi projetado usando técnicas pouco eficientes e não podemos mais evitar o problema comprando hardware melhor.
fonte
Preocupe-se primeiro com a correção 1 , depois com a manutenção, depois com a segurança e a confiabilidade e depois pense no desempenho. Aplique esse pedido a cada pedaço de código à medida que o desenvolve. É possível que uma solução de alto desempenho possa naturalmente resultar em simplesmente manter as coisas claras e diretas.
80% do desempenho está escolhendo o algoritmo e a estrutura de dados corretos para o problema em questão; um quicksort mal otimizado ainda está sendo eliminado de uma bolha altamente otimizada no caso médio (no pior caso, é um empate).
O que todo mundo no SO está tentando entender é a mentalidade "que é mais rápida, ++ p ou p ++", na qual as pessoas ficam tão envolvidas em superar o compilador que perdem o controle do problema maior, resultando em um código quebradiço, bug - montado, errado e, o melhor de tudo, não muito mais rápido do que uma solução mais direta teria sido. Eu lidei com esse tipo de código em primeira mão; um exemplo era tão frágil que não conseguimos fazer nenhuma alteração sem quebrá-lo completamente.
1 Onde "correção" significa "cumprir a especificação", que não é sinônimo de "livre de erros".
fonte
Você deve começar a pensar em desempenho quando souber o que é "bom" desempenho. Em outras palavras, seria errado começar a pensar em desempenho antes de identificar quais são os seguintes limites:
Depois de identificar quais são esses limites, você também identifica a métrica que está usando para medir o desempenho. Isso significa que você pode configurar alguns testes de desempenho automatizados que podem ser executados várias vezes ao dia. Isso lhe dirá se você está ficando melhor ou pior.
Para criar essas métricas, você precisa entender o que seu sistema precisa fazer. Por exemplo, são necessárias métricas de desempenho absolutas (resposta dentro do tempo X) ou são necessárias medições de taxa de transferência (respostas X por tempo Y)? As otimizações de produtividade e tempo absoluto exigem abordagens diferentes e, se você não sabe o que é realmente importante, pode estar otimizando da maneira errada.
fonte
Você provavelmente já ouviu falar que a otimização prematura é a raiz de todo mal. A questão é o que o torna prematuro? Na minha opinião, nunca é uma má idéia pensar em desempenho, mas não se preocupe excessivamente até que seu código funcione. Quando funcionar, faça alguns testes de carga pesada, identifique e identifique gargalos e faça suas otimizações de desempenho.
Dito isto, não há nada de errado em pensar em desempenho durante o estágio inicial de codificação, se você conhece certas técnicas que farão uma diferença real. Por exemplo, escolhendo uma estrutura de armazenamento de uma biblioteca em detrimento de outra, porque a experiência passada ensinou que uma delas é mais rápida / usa menos RAM que a outra. Ou criar um sistema de armazenamento em cache simples (você pode torná-lo mais sofisticado se necessário em testes posteriores) para dados que você conheceserá acessado muito e seria muito melhor armazenado em cache. Dessa forma, você não se preocupa muito com o desempenho (pelo menos não inicialmente), mas usa dicas e truques que aprendeu ao longo do caminho em outros projetos. Tente mantê-las simples para facilitar a inclusão durante o desenvolvimento inicial e também oferecer alguns benefícios.
fonte
O desempenho deve ser detalhado nas especificações relacionadas ao sistema e ao usuário do seu documento de requisitos. Conheço muitas pessoas que zombam da idéia de realizar a Análise de Requisitos no desenvolvimento de um aplicativo, mas surpreendentemente esse documento responde de forma concisa a que e onde você deve dedicar seus recursos relacionados ao desempenho, à medida que o aplicativo se aproxima da conclusão. E responderá a essa pergunta em tempo hábil
A documentação de requisitos poupará centenas de horas de tempo que seriam desperdiçadas em processos não essenciais.
fonte
Uma abordagem equilibrada seria melhor. O desempenho é importante, mas não tão importante quanto fazer as coisas, portanto:
Essa é minha abordagem comum de desempenho versus funcionalidade e, em geral, tudo depende do que o programa faz e de verificar se há necessidade de melhorar as coisas e quanto tempo isso me custaria.
Vamos pensar em um site de perguntas e respostas como este, eu acho que os que estão por trás dele certamente pensaram muito em como fazer uma pergunta e obter a resposta o máximo de tempo / custo possível. Mas, ao pensar em notificações, realmente não importa muito se as notificações aparecerem de vez em quando e lhe informarem que há uma nova resposta ou algo assim.
fonte
Há uma maneira de adiar com segurança o pensamento sobre desempenho: usar idiomas específicos do domínio sempre que possível.
Se a maior parte do seu desenvolvimento puder ser realizada com seus próprios pequenos DSLs, e eles forem projetados o suficiente para expressar o domínio do problema da forma mais genérica e de alto nível, é possível obter um protótipo funcional primeiro, sem sequer pensar em desempenho e, em seguida, aprimore apenas as implementações de suas DSLs, não o código de domínio do problema real.
É uma abordagem muito melhor do ponto de manutenção do veiw também.
fonte
Você deve levar em consideração o desempenho. No entanto, você deve desenhar uma linha para marcar o final da sintonia, pois (geralmente) seu tempo é mais importante que o do computador.
Um artigo de texto realmente bom sobre desempenho é: The Computer Performance Shell Game .
fonte
A maneira "melhor" é um termo muito carregado, e a resposta pode ser altamente dependente de fatores desconhecidos até o tempo de execução.
A lista continua e continua.
O que você pode fazer, é escrever "a coisa mais simples que poderia funcionar" a partir do conhecimento que atualmente não têm, e fazê-lo em um modular de moda que você possa facilmente reorganizar quando você sabe mais. Note que a coisa "mais simples" não é necessariamente simples!
fonte
É sempre algo que você deve ter em mente. Eu acho que o que a maioria das pessoas está tentando dizer é que não faz muito sentido passar dois dias tentando otimizar algo que você nem sabe que está quebrado. Depois que você tiver um produto em execução e puder fazer alguns testes de usabilidade, isso deve mostrar onde você está tendo problemas de desempenho. Em seguida, depois de identificar os verdadeiros problemas de desempenho, você pode direcionar as otimizações que precisa executar.
fonte
Em teoria, pelo menos, você deve começar a pensar em desempenho quando estiver no teste beta e não antes.
Esta não é, no entanto, licença para tomar más decisões de design. Por exemplo, o uso de uma string NVARCHAR como chave primária é um caminho seguro para um desempenho ruim; Dito isto, é um hábito imundo, independentemente dos problemas de desempenho, e você não deve usá-lo em primeiro lugar.
Se o seu design seguir as práticas recomendadas convencionais (tudo na 3ª forma normal, informações apropriadas ocultas nas suas aulas, uso mínimo de singletons, etc.), e houver um problema de desempenho posteriormente, será fácil lidar com isso (crie um índice aqui, implementar um cache lá).
HTH
fonte
Depende. É útil ter em mente a regra 80/20: a maioria (digamos 80%) do código no aplicativo nunca será executada com frequência suficiente para fazer qualquer diferença perceptível no desempenho. Você precisa se concentrar nos 20% restantes, onde o aplicativo deve gastar cerca de 80% do seu tempo de execução.
Você pode identificar antecipadamente alguns dos pontos de acesso óbvios do desempenho, como se você soubesse que um determinado cálculo será repetido milhões de vezes. Nesses casos, definitivamente vale a pena pensar em otimizá-lo antecipadamente, escolhendo as estruturas e algoritmos de dados corretos para o trabalho.
No entanto, essa otimização é mais uma atividade de design. O que geralmente é inútil são as micro-otimizações, nas quais alguém gasta uma quantidade excessiva de tempo com truques inteligentes e complicados em nome do "ganho de desempenho". Especialmente se for feito sem as medições apropriadas antes e depois, essas alterações podem não fazer diferença ou realmente tornar o aplicativo mais lento em circunstâncias da vida real.
fonte
Depende do estágio de desenvolvimento em que você está
1) Se você, na construção da funcionalidade do seu software, o mantém funcionando, verifique se ele funciona bem (isto é, desejado e com eficiência).
2) Uma vez que os blocos de construção sejam integrados, você terá dicas sobre os recursos, então você tem espaço para otimização.
fonte
Se você precisa começar a pensar em desempenho, está com problemas. Você deve estar pensando em desempenho o tempo todo. De fato, suspeito que bons programadores vão pensar em desempenho, mesmo quando não pretendiam, da maneira "homens pensam em sexo a cada sete segundos".
O importante é que ações você tomará com base em todo esse pensamento. Pensamentos são baratos, mas as ações podem quebrar o código e estourar os prazos.
Na maioria das vezes, a única ação sensata é não fazer nada: você identificou que seu trecho de código não será chamado com freqüência suficiente para que os problemas de desempenho sejam observáveis - talvez seja um trecho de código de inicialização que seja executado uma vez por computador para 1% da sua base de usuários em potencial, talvez seja um pequeno código de servidor redundante afogado em um mar de acessos lentos ao banco de dados, talvez seja apenas uma atribuição de número inteiro em uma seção não crítica do código.
Freqüentemente, você suspeita que uma determinada operação possa causar um problema de desempenho que pode ser resolvido com uma simples alteração. Por exemplo, a sensação incômoda de que executar uma consulta SQL complexa em todas as solicitações ou solicitar o mesmo pedaço de dados de um dicionário duas vezes será ruim para você. É aqui que o conhecimento das técnicas de otimização é útil, e talvez a conclusão mais surpreendente ocorra:
Se você conhece uma técnica rápida que certamente irá melhorar o desempenho de um pedaço de código, não faça isso.
Se você pode pensar nisso agora, certamente poderá fazê-lo em cinco minutos depois. Mantê-lo fora do código (mas, talvez, em um
// TODO
comentário) deixa o código mais limpo e economiza tempo anterior para trabalhar em outro recurso, sem perder tempo se você acabar jogando o código fora mais tarde. Se o código original causar problemas de desempenho ao ser testado, volte e aplique sua técnica rápida.Não estou dizendo aqui que você deve evitar escrever código idiomático apenas porque é mais rápido. Escreva código idiomático de acordo com as práticas recomendadas que melhoram a produtividade e a legibilidade e reduzem os erros. Apenas se você tiver uma escolha entre o código idiomático do manual e uma alternativa mais rápida, mas fácil de escrever, sempre busque a legibilidade em vez da velocidade.
A única situação difícil é quando parece não haver uma maneira fácil de melhorar o desempenho do código e, no entanto, é dolorosamente óbvio que um pedaço de código será quebrado assim que for entregue - um percurso completo do banco de dados a cada clique, centenas de solicitações SQL por página no site ou qualquer coisa igualmente terrível. É aqui que você realmente precisa parar e pensar um pouco mais. Normalmente, esses são problemas de arquitetura que não podem ser resolvidos em escala local. Confirme suas suspeitas com um pico ou protótipo rápido, procure experiências semelhantes e soluções comuns e considere uma mudança de arquitetura ou uma queda de recursos.
fonte
IMHO, é importante pensar no desempenho antes de implementar o sistema, mas apenas pensar. Você deve analisar o aplicativo e descobrir quais poderiam ser possíveis gargalos de desempenho.
Em seguida, implemente o sistema o mais simples possível. Se surgirem problemas de desempenho, otimize.
Por exemplo, digamos que você tenha um cliente GUI que obtém dados através de algum tipo de serviço (SOAP, REST HTTP, etc.). Então, o mais importante para o alto desempenho / escalabilidade é ter o menor número possível de chamadas, fazendo com que cada chamada retorne muitos dados, em vez de muitas chamadas retornando um pouco de informação cada, ou seja, prefira uma comunicação robusta à falada.
Ao implementar esse tipo de sistema, eu não me importaria muito com o número de chamadas entre o sistema. Mas eu me certificaria de que a base de código tornasse fácil refatorar / otimizar quando surgir a necessidade.
fonte
Você deve pensar no desempenho de maneiras muito gerais desde o início. Você deve selecionar estruturas de dados e algoritmos que funcionem bem para seu aplicativo e sejam razoavelmente eficientes. Algoritmos são fundamentais para o software, e estruturas de dados mais ainda. Provavelmente, você precisará reescrever grandes se precisar fazer grandes alterações, enquanto detalhes menores podem ser reescritos com mais facilidade.
Você também pode querer adquirir hábitos eficientes, mas isso dependerá do idioma. Em C ++, por exemplo, "++ i;" como uma declaração ou expressão autônoma é sempre pelo menos tão bom quanto "i ++;" e pode ser potencialmente muito mais eficiente. Na maioria dos casos, você deve escrever um código claro e confiar no compilador. Adquirir o hábito de se preocupar com microeficiências quase certamente causará mais problemas do que resolve. Para aplicativos de desktop, o compilador é pelo menos tão inteligente quanto você sobre coisas como
i >> 1
vs.i / 2
ou a melhor maneira de melhorar o desempenho é obter um compilador melhor, portanto, não se preocupe.Além disso, não se preocupe muito até ter algo que possa testar. Nesse momento, você pode criar um perfil do programa para ver onde estão os pontos de acesso e, provavelmente, ter uma idéia sobre se você tem um programa de desempenho ou não. Se você precisar melhorar o desempenho, descubra onde o programa está passando a maior parte do tempo e melhore as coisas lá. Se você projetou com eficiência global adequada e escreveu bem o programa, está mudando apenas uma parte relativamente pequena do programa.
fonte
Eu acho que o melhor que você pode fazer é seguir as boas práticas de design (por exemplo, não faça coisas que você sabe que prejudicarão o desempenho) até conseguir que algo funcione. Se você não pode medir a melhoria, não pode fazê-la. Uma vez que você tem algo com o qual pode testar, geralmente é uma boa ideia fazer uma análise de perfil e ter uma idéia de onde estão os pontos quentes (se houver). Se algo surgir em você, considere refatorar ou reescrever a área do problema, mas se não for muito ruim (apenas porque o código passa 90% do tempo em dois ou três métodos não significa nada se o desempenho for adequado) então continue desenvolvendo. Algo que já vi mais de uma vez são desenvolvedores que passam dias otimizando a parte mais complexa do sistema,
fonte
Quando devo começar a pensar sobre isso? Quanto esforço devo colocar nele? Isso depende da escala de Cockburn do projeto. (Em outras palavras, qual é o risco de não ter um bom desempenho?)
Aprenda os fundamentos com bastante antecedência (consulte a resposta de Robert Harvey ). Para aplicar o pensamento orientado ao desempenho durante vários estágios do desenvolvimento de software, o desenvolvedor precisa conhecê-lo de dentro para fora, para que o processo de pensamento não seja prejudicado por essas considerações extras. (Em outras palavras, comece a pensar no desempenho antes que o projeto seja concebido.)
Durante o estágio inicial de desenvolvimento, faça uso liberal de ferramentas de perfil de desempenho e acompanhe o histórico de estatísticas. Preste atenção especial na organização dessas informações para torná-las úteis para tomadas de decisão posteriores.
Então, dependendo da natureza do seu projeto e da escala Cockburn:
Prototipagem rápida, ou "código aberto como se não houvesse amanhã", ou desenvolvimento interno com baixo impacto nos negócios: basta manter as estatísticas. Ainda não pense em desempenho. Implemente a função da maneira mais fácil. Fique com o primeiro algoritmo que lhe vier à cabeça.
Aplicativos de desktop, que exigem uma abordagem consistente e abrangente do desempenho. Não precisa ser altamente otimizado; no entanto, deve haver o menor número possível de "travamentos" (falta de resposta).
Computação de alto desempenho, que requer o máximo desempenho do hardware.
fonte
No inicio. Identifique as características de desempenho necessárias. Se você não conseguir identificar o destino, precisará voltar para entender melhor seus requisitos ou adiar até conhecer seus requisitos de componente com o risco de reescrever. Então teste. Não otimize, teste. Se você codificar no teste de desempenho, otimize. Com uma estrutura de teste em prática, o uso das ferramentas de monitoramento de desempenho existentes deve facilitar a tarefa.
Mantenha os testes de desempenho em vigor durante toda a vida útil do projeto como um teste de regressão. O código de manutenção é notório por desencadear problemas de desempenho porque as 'correções' geralmente têm um foco muito restrito.
fonte
Eu sempre confio em uma fórmula simples:
... naquela ordem.
De acordo com c2 , esta formulação é atribuída a Kent Beck .
fonte