ti-enxame.com

Quando devo me preocupar com o desempenho?

Por muito tempo em lugares como Java's IRC channel , SO, e outros lugares, me disseram algo como "Preocupe-se com a aparência do código e sua legibilidade/compreensibilidade agora, e desempenho mais tarde se for absolutamente necessário. ”Então, por muito tempo, eu não tenho realmente OCD sobre o desempenho de meus pequenos aplicativos de desktop ou web, apenas removendo o obviamente ineficiente.

A maioria das respostas são "E quanto à escalabilidade?". Esse é um ponto legítimo, mas se meu aplicativo foi construído apenas para analisar, digamos, arquivos de 10.000 linhas, devo tornar meu código uma bagunça para a pequena porcentagem de pessoas que vão enfiar em um arquivo de 1.000.000 de linhas?

Minha pergunta principal é quando devo trocar as maneiras fáceis, mas um tanto ineficientes de fazer tarefas, por bestas gigantes e complicadas que fazem as coisas extremamente rapidamente, mas destroem todas as formas possíveis de atualização e tornam o código excessivamente difícil e sujeito a reescrever de qualquer maneira pelo próximo desenvolvedor?

16
TheLQ

Preocupe-se com o desempenho quando se tornar um problema.

Se você escrever um pequeno aplicativo para processar 10.000 arquivos de linha e obter um arquivo de 1.000.000 de linhas a cada 100 arquivos, provavelmente não importa que demore mais para processar aquele único arquivo. No entanto, se você recebe regularmente arquivos 5 a 10 vezes maiores do que o inicial e seu aplicativo está demorando muito para fazer seu trabalho, comece a criar o perfil e a otimizar.

Agora, eu disse "muito tempo para fazer seu trabalho". A decisão é do usuário ou da organização patrocinadora. Se estou realizando uma tarefa e demoro 5 minutos para fazer algo quando levava 3 sem o software ou com uma ferramenta diferente, provavelmente arquivaria um relatório de bug ou solicitação de manutenção para que isso melhorasse.

Se você for o usuário, depende de você quanto tempo deseja que o software demore para fazer seu trabalho - somente você pode decidir se deseja que seja feito mais rápido ou se está disposto a esperar mais para ter um código mais legível.

23
Thomas Owens

Minha pergunta principal é quando devo trocar as maneiras fáceis, mas um tanto ineficientes de fazer tarefas, por bestas gigantes e complicadas que fazem as coisas extremamente rapidamente, mas destroem todas as formas possíveis de atualização e tornam o código excessivamente difícil e sujeito a reescrever de qualquer maneira pelo próximo desenvolvedor?

Geralmente é uma falsa dicotomia . Você pode escrever um código maravilhosamente eficiente, legível e sustentável. Você pode escrever pilhas de bagunça maravilhosamente ineficientes e impossíveis de manter.

Ao lidar com problemas de desempenho, geralmente tento pensar sobre o problema de negócios que estou resolvendo. Como meu software se comportará quando meus clientes o usarem. O desempenho dos meus aplicativos deixará Jacob Nielsen feliz ?

10
Sam Saffron

Um truísmo que aprendi estudando microprocessadores na faculdade e que permaneceu comigo: "Faça o caso comum rápido. Faça o caso incomum correto."

Contanto que você tenha apenas uma pequena porcentagem de usuários sufocando seu código com uma entrada duas ordens de magnitude maior do que o que ele deveria suportar, não se preocupe. Certifique-se de que ele lida com a entrada corretamente se eles fornecerem por tempo suficiente e não deixe nada corrompido e inutilizado se encerrar o trabalho antes de terminar.

Mas, mais uma vez as pessoas começam a usá-lo dessa forma (ou começam a dizer "Sabe, adoraria usar essa ferramenta que você escreveu nos meus relatórios semanais de TPS, mas leva um dia horrível"), é aí que você começa a considerar trocar a facilidade de manutenção por ganhos de desempenho.

5
BlairHippo

Minha pergunta principal é quando devo trocar as maneiras fáceis, mas um tanto ineficientes de fazer tarefas, por bestas gigantes e complicadas que fazem as coisas extremamente rapidamente, mas destroem quaisquer formas possíveis de atualização e tornam o código excessivamente difícil e sujeito a reescrever de qualquer maneira pelo próximo desenvolvedor?

"Preocupar-se com a aparência do código e sua legibilidade/compreensibilidade agora, e com o desempenho posterior se for absolutamente necessário" é a saída mais fácil e geralmente inútil. um bom design será fácil de manter, fácil de ler e eficiente.

o desempenho é um componente comum de um bom design. se o seu programa for lento e desperdiçador, não será reutilizável. quando você precisa consertar aquela bagunça, você força as atualizações em seus clientes, a menos que seja muito tempo consumindo para eles atualizarem. aquele programa lento se torna a grande bagunça que é muito caro para melhorar. então eles escolhem uma alternativa porque ela não atende às suas necessidades. diagnosticar, atualizar e lidar com os efeitos colaterais de melhorias em um projeto ruim geralmente superam o tempo de desenvolvimento inicial para escrevê-lo para ser eficiente, funcionar corretamente e ter um projeto geralmente bom. esse programa é altamente reutilizável e requer baixa manutenção (win).

portanto, a resposta curta à sua pergunta é "não desperdice. escreva para reutilizar. não há problema em ser preguiçoso ao prototipar/desenvolver provas de conceito, mas não use esse protótipo para código de produção.".

esteja ciente e evite o desperdício de projetos ao escrever programas de produção e programas que você pretende reutilizar. durante a implementação é o momento ideal para escrever seu programa para não ser um desperdício - você tem uma ideia clara dos detalhes e de sua operação, e é muito doloroso e ineficaz corrigir depois de escrito. muitas pessoas acreditam que um pouco de definição de perfil (talvez) no final ou se houver um problema é adequado, quando normalmente é muito demorado redesenhar/mudar e as ineficiências são tantas e tão difundidas que você não entende o programa bem com base nos resultados de um perfil. essa abordagem leva pouco tempo durante a implementação e (supondo que você já tenha feito isso o suficiente) normalmente resulta em um design que é várias vezes mais rápido e pode ser reutilizado em muitos outros contextos. não desperdiçar, escolher bons algoritmos, pensar em suas implementações e reutilizar as implementações certas são todos componentes de um bom design; tudo isso melhora legibilidade, manutenção e reutilização mais frequentemente do que prejudica.

1
justin

Se você está trabalhando em áreas genuinamente críticas para o desempenho, não pode colocar a eficiência em segundo plano. É uma das coisas mais críticas a se pensar ao projetar logo no início desses casos e de maneiras que se relacionam com a sustentabilidade do resultado final.

Você não pode projetar e implementar um servidor em grande escala e apenas começar a escrever um código fácil e bem documentado que usa funções de bloqueio para tudo com um bloqueio de thread global que bloqueia todo o sistema para processar cada solicitação individual do cliente, sem colocar nenhum pensamento qualquer em estado compartilhado, contenção de thread e assincronicidade. Essa é uma receita para o desastre e uma necessidade de redesenhar e reescrever a maior parte do código bem documentado que você escreveu de maneiras que poderiam levar à base de código mais difícil de manter imaginável, atormentada por condições de corrida e impasses como resultado de tentativas para alcançar a eficiência necessária em retrospectiva, em vez de apenas ter pensado em designs eficientes, simples e funcionais com antecedência.

Uma equipe de desenvolvimento de jogos com 8 meses de produção com um mecanismo que só funciona 2 quadros por segundo em seu hardware mais robusto com 32 núcleos, enquanto tende a parar por 15 segundos toda vez que a tela fica ocupada, provavelmente não obterá instantaneamente um produto utilizável apenas consertando um pequeno ponto de acesso localizado. As chances são de que seu design seja FUBAR de maneiras que garantem uma revisitação épica da prancheta e das mudanças de design que podem se espalhar em todos os cantos da base de código.

Com John Carmack, ele falou uma vez sobre como uma demonstração de tecnologia tem que ser executada no mínimo de centenas a milhares de quadros por segundo para integrá-la à produção. Essa não é uma obsessão doentia com eficiência. Ele sabe de antemão que os jogos precisam ser executados, em sua totalidade, a 30+ FPS para que os clientes considerem isso aceitável. Como resultado, um pequeno aspecto como um sistema de sombra suave não pode rodar a 30 FPS, ou então o jogo como um todo não pode ser rápido o suficiente para fornecer o feedback em tempo real necessário. É inutilizável até atingir a eficiência necessária. Em tais áreas de desempenho crítico, onde há um requisito fundamental de eficiência, uma solução que não consegue atingir a velocidade adequada não é melhor do que outra que não funciona, pois ambas são completamente inutilizáveis. E você não pode projetar um sistema de sombra suave eficiente que rode a centenas a milhares de quadros por segundo, conforme necessário para um mecanismo de jogo em tempo real, a menos que você pense muito antes de sua eficiência. Na verdade, nesses casos, 90 +% do trabalho é orientado em torno da eficiência, pois é trivial criar um sistema de sombra suave que funcione bem a 2 horas por quadro usando rastreamento de caminho, mas você não pode esperar ajustá-lo para rodar a centenas de quadros por segundo sem uma mudança totalmente diferente na abordagem.

Quando a eficiência é uma parte fundamental do design de um aplicativo, você não pode esperar obter eficiência em retrospectiva sem perder muito mais tempo do que economizou ao ignorá-la, já que não pode esperar obter um design funcional em retrospecto. Ninguém diz, "eu não há problema em adiar a reflexão sobre o design para mais tarde. Apenas documente bem o seu código e poderá criar um design adequado mais tarde." Mas em arquiteturas de desempenho crítico, isso é o que você está fazendo efetivamente se não colocar muito cuidado e pensamento em projetos eficientes antecipadamente.

Agora, isso não significa que você precisa micro-sintonizar suas implementações logo de cara. Para obter detalhes de implementação, há muito espaço para iterar em direção a soluções mais rápidas após a medição, desde que o design não precise ser alterado e, frequentemente, essa é a maneira mais produtiva de fazer isso. Mas, no nível de design, isso significa que você deve pensar o suficiente em como o design e a arquitetura se relacionarão com a eficiência desde o início.

A principal diferença aqui é design. Não é fácil fazer grandes mudanças nos designs retrospectivamente, pois os designs acumulam dependências, e as dependências serão interrompidas se o design mudar. E se um projeto exige que seja razoavelmente eficiente ou, em alguns casos, que sua qualidade seja amplamente medida por sua eficiência, então você não deve esperar conseguir um projeto adequado em uma reflexão tardia. Com quaisquer produtos competitivos onde a eficiência é um grande aspecto da qualidade, sejam sistemas operacionais ou compiladores ou processadores de vídeo ou raytracers ou motores de jogos ou motores de física, pensamentos sobre eficiência e representações de dados foram meticulosamente pensados ​​desde o início. E, nesses casos, não é uma otimização prematura pensar tanto na eficiência desde o início. Era colocar tal pensamento exatamente no momento mais produtivo para fazê-lo, e desde o início.

0
user204677

Tento tornar o código legível - dane-se o desempenho.

Quando e se o código for muito lento, irei refatorá-lo para ser mais rápido. Normalmente, o processo de refatoração é seguido de muitos comentários, pois o código tende a ser menos legível.

0
Josip Medved

Hum - Nunca?

Sério, o código deve sempre ser escrito de forma a ser facilmente compreendido e mantido.

Com relação a quando lidar com problemas de desempenho, lidar com eles depois de identificá-los, não pré-otimize seu código porque então você estará apenas adivinhando onde estão os problemas de desempenho.

Se o seu código for escrito de forma a ser claro, conciso, compreensível e fácil de manter, você ou outro programador não deve ter problemas em refatorar o código para torná-lo mais eficiente.

0
Noah Goodrich

Eu normalmente escrevo código para ser legível em primeiro lugar. Se, e somente se, eu descobrir que o programa é executado muito lento para fazer seu trabalho, eu crio o perfil e otimizo. Dito isso, não há nada de errado em adquirir o hábito de realizar otimizações comuns que não afetam a legibilidade do seu código. Ou seja, se um trecho de código pode ser escrito de duas maneiras igualmente (ou quase igualmente) legíveis, escolha aquela que geralmente é mais rápida.

Por exemplo, em Python, as compreensões de lista (ou expressões geradoras) tendem a ser mais rápidas do que o loop for equivalente, então eu uso compreensões de lista onde posso, se elas não afetam a legibilidade (por exemplo, eu não não aninhe as compreensões de lista, se puder evitar, e use um loop for em vez disso, porque as compreensões de lista aninhada podem ser difíceis de analisar mentalmente).

Da mesma forma, tipos de dados imutáveis ​​tendem a ser mais rápidos do que os mutáveis, então eu uso tipos de dados imutáveis ​​onde posso.

0
Chinmay Kanchi