Quando devo me preocupar com desempenho?


16

Durante muito tempo em lugares como o canal IRC de Java , 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 estado realmente obcecado com o desempenho para meus pequenos aplicativos da área de trabalho ou da Web, apenas removendo o obviamente ineficiente.

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

Minha principal pergunta é quando devo trocar as maneiras fáceis, mas um tanto ineficientes, de realizar tarefas por grandes bestas gigantes complicadas que fazem as coisas com extrema rapidez, mas destroem todas as formas possíveis de atualização e tornam o código excessivamente difícil e propenso a ser reescrito pelo próximo desenvolvedor?

Respostas:


23

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

Se você escreve um aplicativo pequeno para processar 10.000 arquivos de linha e obtém um arquivo de 1.000.000 de linhas a cada 100º arquivo, provavelmente não importa que demore mais para processar esse arquivo. No entanto, se você está obtendo regularmente arquivos 5 a 10 vezes maiores que o inicialmente e seu aplicativo está demorando muito para fazer seu trabalho, inicia a criação de perfil e a otimização.

Agora, eu disse "muito tempo para fazer o seu trabalho". Isso depende do usuário ou da organização patrocinadora. Se estou fazendo uma tarefa e levo 5 minutos para fazer alguma coisa quando me levam 3 sem o software ou com uma ferramenta diferente, provavelmente arquivarei um relatório de bug ou uma solicitação de manutenção para que isso melhore.

Se você é o usuário, depende de quanto tempo você deseja que o seu software faça - apenas você pode decidir se deseja que seja feito mais rapidamente ou se deseja esperar mais para ter um código mais legível.



Eu começar a perfilar e otimizar Se 1) o trabalho leva muito tempo 2) um dos recursos de hardware está no máximo (por exemplo, 100% da CPU)
A. Binzxxxxxx

10

Minha principal pergunta é quando devo trocar as maneiras fáceis, mas um tanto ineficientes, de realizar tarefas por grandes bestas gigantes complicadas que fazem as coisas com extrema rapidez, mas destroem todas as formas possíveis de atualização e tornam o código excessivamente difícil e propenso a ser reescrito pelo próximo desenvolvedor?

Isso geralmente é uma dicotomia falsa . Você pode escrever um código maravilhosamente eficiente, legível e de manutenção. Você pode escrever montes de bagunça maravilhosamente ineficientes e inatingíveis.

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


5
++ FALSA DICOTOMIA! Eles nunca aprenderão? Quando você encontra e corrige um problema de desempenho, o código não é apenas mais rápido, é melhor . Só me arrependo de ter apenas uma votação a dar!
precisa saber é o seguinte

+1 por escrever que geralmente é uma dicotomia falsa ... nem sempre, mas geralmente.
Dan Rosenstark

1
-1 para escrever geralmente é uma falsa dicotomia - o fato é que geralmente está correta e apenas em casos raros uma falsa dicotomia. Em mais de 30 anos de minha carreira em programação, vi muitas otimizações de desempenho "bem-intencionadas", que de fato dificultaram o entendimento e a manutenção do código (e muitas vezes otimizavam algo que era totalmente desnecessário de ser otimizado).
Doc Brown

5

Um truísmo que aprendi estudando microprocessadores na faculdade que ficava comigo: "Acelere o caso comum. Corrija o caso incomum".

Contanto que você tenha apenas uma pequena porcentagem de usuários bloqueando seu código com entrada de duas ordens de magnitude maiores do que o que ele deveria manipular, não se preocupe. Certifique-se de que ele lida com a entrada corretamente, se a duração for longa o suficiente, e não deixe nada corrompido na inutilidade se matar a tarefa antes que ela termine.

Mas, mais e mais pessoas começam a usá-lo dessa maneira (ou começam a dizer "Você sabe, eu adoraria usar a ferramenta que você escreveu nos meus relatórios semanais do TPS, mas demora todo o dia"), é quando você começa a considerar a facilidade de manutenção de troca para obter ganhos de desempenho.


1

Minha principal pergunta é quando devo trocar as maneiras fáceis, mas um tanto ineficientes, de realizar tarefas por grandes bestas gigantes complicadas que fazem as coisas com extrema rapidez, mas destroem todas as formas possíveis de atualização e tornam o código excessivamente difícil e propenso a ser reescrito pelo próximo desenvolvedor?

"Preocupe-se com a aparência do código e sua legibilidade / compreensão agora, e o desempenho mais tarde, 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 inútil, não será realmente reutilizável. quando você precisa consertar essa bagunça, força as atualizações em seus clientes, a menos que seja tempo demais para que elas sejam atualizadas. esse programa lento se torna a grande bagunça que é muito cara para melhorar. então eles escolhem uma alternativa porque não atende às suas necessidades. diagnosticar, atualizar e lidar com os efeitos colaterais das melhorias em um design inadequado geralmente superam o tempo de desenvolvimento inicial para que ele seja eficiente, funcione corretamente e tenha um design geralmente bom. esse programa é altamente reutilizável e requer baixa manutenção (vitória).

portanto, a resposta curta para sua pergunta é "não seja um desperdício. escreva para reutilização. tudo bem ser preguiçoso ao prototipar / desenvolver provas de conceitos, mas não use esse protótipo para código de produção".

esteja ciente e evite projetos desnecessários 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 idéia clara dos detalhes e de seu funcionamento, e é realmente doloroso e ineficaz corrigir após a gravação. muitas pessoas acreditam que um pouco de criação de perfil (talvez) no final ou se houver um problema é adequado, quando geralmente é muito demorado para reprojetar / alterar 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ê tenha feito isso o suficiente) normalmente resulta em um design que é várias vezes mais rápido e é reutilizável em muitos outros contextos. não sendo um desperdício, escolher bons algoritmos, refletir sobre suas implementações e reutilizar as implementações corretas são todos componentes do bom design; todos os quaismelhora a legibilidade, a manutenção e a reutilização com mais freqüência do que prejudica.


0

Eu tento tornar o código legível - o desempenho seja danado.

Quando e se o código for muito lento, eu o refatorarei para ser mais rápido. Geralmente, o processo de refatoração é seguido com muitos comentários, pois o código tende a ser menos legível.


0

Hum - nunca?

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

No que diz respeito a quando lidar com problemas de desempenho, lide com eles depois de identificá-los, não otimize previamente seu código, pois você estará apenas adivinhando onde estão os problemas de desempenho.

Se o seu código for escrito de forma clara, concisa, compreensível e sustentável, você ou outro programador não terá problemas em refatorar o código para torná-lo mais eficiente.


3
Eu não concordo com isso. Um requisito de desempenho é um requisito não funcional válido para um sistema.
Thomas Owens

Tecnicamente, se houver um requisito relacionado ao desempenho claramente definido, pode-se dizer que você identificou um problema de desempenho e deve explicá-lo em sua solução. O que estou falando é ficar esperto com antecedência, para que você possa evitar problemas 'potenciais' inespecíficos.
Noah Goodrich

Ah Sim, você está absolutamente certo nesse caso. Você não se preocupa com as possibilidades, porque existem muitas, mas concentre-se no que sabe.
Thomas Owens

0

Normalmente escrevo código para ser legível em primeiro lugar. Se, e somente se, eu achar que o programa está muito lento para executar seu trabalho, perfil e otimizo. Dito isto, não há nada de errado em adquirir o hábito de executar otimizações comuns que não afetam a legibilidade do seu código. Ou seja, se um pedaço de código puder ser escrito de duas maneiras igualmente (ou quase igualmente) legíveis, escolha aquele que geralmente é mais rápido.

Por exemplo, no Python, as compreensões de lista (ou expressões geradoras) tendem a ser mais rápidas que o forloop equivalente ; portanto, utilizo as compreensões de lista onde posso, se elas não afetam a legibilidade (por exemplo, não aninho as compreensões de lista se Eu posso evitá-lo e, em vez disso, usar um loop for porque é difícil analisar mentalmente as compreensões de lista aninhadas).

Da mesma forma, os tipos de dados imutáveis ​​tendem a ser mais rápidos que os mutáveis, então eu uso tipos de dados imutáveis ​​sempre que possível.


0

Se você estiver trabalhando em áreas genuinamente críticas para o desempenho, não poderá adiar a eficiência como uma reflexão tardia. É uma das coisas mais importantes a se pensar ao projetar desde o início nesses casos e de maneiras relacionadas à manutenção do resultado final.

Você não pode projetar e implementar um servidor em larga escala e apenas começar a escrever código fácil e bem documentado, que apenas usa funções de bloqueio para tudo com um bloqueio de encadeamento global que bloqueia todo o sistema para processar cada solicitação de cliente individual sem colocar nenhuma pensou em qualquer estado compartilhado, contenção de threads e assincronicidade. Essa é uma receita para o desastre e a necessidade de reprojetar e reescrever a maior parte do código bem documentado que você escreveu, de maneira a levar à base de código mais difícil de manter que se possa imaginar, atormentada pelas condições de corrida e impasses como resultado de tentar para alcançar a eficiência necessária em retrospectiva, em vez de apenas pensar em projetos eficientes, simples e funcionais antecipadamente.

Uma equipe de desenvolvimento de jogos com 8 meses de produção com um mecanismo que passa apenas 2 quadros por segundo em seu hardware mais robusto com 32 núcleos e tem uma tendência a parar por 15 segundos cada vez que a tela fica ocupada, é improvável que você obtenha instantaneamente um produto utilizável apenas consertando um pequeno ponto de acesso localizado. As chances são de que seu design seja FUBAR de maneira a garantir uma revisão épica da prancheta e as alterações de design que poderiam se espalhar em todos os cantos da base de código.

Com John Carmack, ele falou uma vez sobre como uma demonstração tecnológica deve 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 por eficiência. Ele sabe de antemão que os jogos precisam rodar na íntegra a mais de 30 FPS para que os clientes considerem aceitável. Como resultado, um pequeno aspecto, como um sistema de sombras suaves, não pode ser executado a 30 FPS, ou 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. Nessas áreas críticas para o desempenho, em que há um requisito fundamental de eficiência, uma solução que falha em atingir a velocidade adequada não é melhor do que aquela que não funciona,. E você não pode projetar um sistema eficiente de sombras suaves que funcione de centenas a milhares de quadros por segundo, conforme necessário para um mecanismo de jogo em tempo real, a menos que você dedique uma quantidade predominante de ideias à sua eficiência. De fato, nesses casos, mais de 90% do trabalho é orientado para a eficiência, já que é trivial criar um sistema de sombra suave que funcione bem a 2 horas por quadro usando o 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 ignorando-a, pois não pode esperar obter um design funcional em retrospectiva. Ninguém diz: " Não há problema em adiar o pensamento para o design até mais tarde. Apenas documente bem seu código e você poderá criar um design adequado mais tarde ". Mas em arquiteturas críticas para o desempenho, é isso que você está efetivamente fazendo se não dedicar muito cuidado e consideração a projetos eficientes antecipadamente.

Agora, isso não significa que você precisa ajustar suas implementações imediatamente. Para detalhes da 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, geralmente, essa é a maneira mais produtiva de fazê-lo. Mas, no nível do design, isso significa que você deve pensar bastante em como o design e a arquitetura se relacionarão com a eficiência desde o início.

A principal diferença aqui é o design. Não é fácil fazer grandes alterações nos designs em retrospectiva, à medida que os designs acumulam dependências, e as dependências serão quebradas se o design mudar. E se um projeto precisa ser razoavelmente eficiente ou, em alguns casos, que sua qualidade seja medida em grande parte por sua eficiência, você não deve esperar conseguir um projeto adequado como uma reflexão tardia. Com qualquer produto competitivo em que a eficiência seja um aspecto enorme da qualidade, sejam sistemas operacionais, compiladores, processadores de vídeo, traçadores de raios, 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 colocar tanto em consideração a eficiência antecipadamente. Ele estava colocando esse pensamento exatamente no momento mais produtivo para fazê-lo,

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.