Como evito a "Intuição de otimização ruim do desenvolvedor"?

22

Vi em um artigo que apresentava essa declaração:

Os desenvolvedores adoram otimizar código e por boas razões. É tão gratificante e divertido. Mas saber quando otimizar é muito mais importante. Infelizmente, os desenvolvedores geralmente têm uma péssima intuição sobre onde realmente estarão os problemas de desempenho em um aplicativo.

Como um desenvolvedor pode evitar essa má intuição? Existem boas ferramentas para descobrir quais partes do seu código realmente precisam de otimização (para Java)? Você conhece alguns artigos, dicas ou boas leituras sobre esse assunto?

Mona
fonte
1
Isso se resume a "Como evito [confiar] nas intuições [ao tomar decisões]?" Simples: você verifica com fatos e dados. Portanto, no caso da otimização, da perspectiva de um desenvolvedor: você faz o benchmark.
haylem

Respostas:

44
  • Use um bom perfilador para identificar métodos caros.
  • Documente quanto tempo os pontos de acesso realmente levaram.
  • Escreva uma implementação mais rápida dos pontos de acesso
  • Documente quanto tempo os pontos quentes demoram agora, espero que não os tornem mais pontos ativos.

Essencialmente, você precisa provar a outras pessoas onde estava o problema e que essa mudança fez com que desaparecesse.

Não sendo capaz de provar uma melhoria, qualifica - na minha opinião pessoal - para reversão imediata à versão original.

Robert Harvey
fonte
51
Ou, de maneira ainda mais simples: "Para evitar intuição ruim de otimização, não use intuição. Meça".
Kyralessa 22/08/11
6
É por isso que a sua é uma resposta e a minha é apenas um comentário. : P
Kyralessa 22/08
2
@ Thomas, se você mexe com legibilidade e facilidade de manutenção, não está olhando exatamente para os problemas de desempenho, está?
3
@ Thomas, eu discordo. Mesmo dentro das especificações, você precisa testar novamente o novo código. Isso não é necessário para o código antigo. Reverter.
2
@ Thorbjørn Após o ajuste de desempenho, você também precisa testar novamente o novo código. Economizar tempo ou memória não faz sentido se você apresentar um defeito.
Thomas Owens
10

A única maneira de saber onde otimizar é criar um perfil do seu código. Em vez de fazer alterações que você acha que trarão benefícios, saiba com certeza onde está o código com pior desempenho e comece por aí.

O Java facilita bastante isso com a ferramenta VisualVM , que foi incluída nos lançamentos recentes do Java Development Kit (JDK). A idéia é descobrir quais métodos são mais chamados e em quais métodos você passa a maior parte do tempo, tanto em seu código quanto em bibliotecas externas. Você também pode obter dados de desempenho na coleta de lixo para ajustar seu coletor e ajustar o espaço mínimo / máximo de heap exigido pelo seu aplicativo.

Thomas Owens
fonte
O VisualVM não está no JRE, apenas no JDK.
1
@ Thorbjørn Ravn Andersen Boa chamada. Eu deveria esclarecer. No entanto, se você estiver desenvolvendo Java, normalmente você tem o JDK instalado (embora possa estar executando o OpenJDK ou similar - não sei se esses vêm com o VisualVM).
Thomas Owens
1
Eu mudo frequentemente os espaços de trabalho no Eclipse, que assumem como padrão o JRE que iniciou o Eclipse. Como é muito mais fácil instalar o JRE do que o JDK, migramos lentamente para um processo de construção de formigas que inclui o compilador Eclipse e, portanto, pode ser executado no JRE comum. Portanto, hoje em dia você pode realmente fazer um trabalho real sem o JDK. O VisualVM pode ser baixado separadamente, facilitando o uso com um determinado Java versino, pois nas JVMs do Windows de 64 bits não é possível conectar-se às JVMs de 32 bits e vice-versa.
9

Como qualquer um aqui está falando sobre criadores de perfil , vou me concentrar nessa parte da questão.

Como um desenvolvedor pode evitar essa má intuição?

Vocês. Faz. não. Em vez disso, você nunca otimiza desde o início .
Repita de novo e de novo e de novo, pois é um mantra religioso.

Você se encontrará fazendo isso e descobrirá que não deveria.
E então novamente.
E de novo.

A Otimização Antecipada é um dos pecados capitais dos programadores .

Ferramentas e outras coisas fazem parte da otimização posterior, que é um ofício estabelecido .

ZJR
fonte
Otimização antecipada do "código complicado", com certeza. Algoritmos de escolha e / ou estruturas de dados que se encaixam no seu problema e (com a carga de processamento esperada) têm boas características de desempenho é algo que deve ser feito antes de você começar a escrever o código.
Vatine 15/09/12
@ Vacina Sim, estive lá. Não, apenas não. Faça o que se encaixa no seu mapa mental do problema em questão. Ele poderia ser o algoritmo mais performance , e desejo-lhe isso, não tem que.
ZJR 15/09/12
parece-me o princípio YAGNI - você não precisa disso!
EL Yusubov 04/10/12
7

Essas ferramentas são chamadas de criadores de perfil . Você pode usá-los para medir quais partes do seu programa demoram mais tempo para serem executadas e, portanto, onde concentrar seus esforços de ajuste.

É igualmente importante medir novamente após as alterações, para verificar se suas alterações têm o efeito pretendido.

Péter Török
fonte
5

Veja também quanta memória seu programa usa, não apenas sua velocidade ou tempo de execução.

Muitos codificadores que trabalham com linguagens de coleta de lixo, como Java, têm a impressão errada de que a coleta de lixo evita vazamentos de memória. Esse não é o caso. Se você mantiver uma referência a um objeto que não precisa mais, ele não será coletado e vazará.

Eu vi aplicativos da Web Java que eram tão vazamentos que executavam o servidor sem espaço de troca!

Se você usar um criador de perfil em tempo de execução e algum tipo de criador de perfil de memória, aprenderá a escrever código mais rápido e mais intuitivo. Isso faz com que seu código tenha maior probabilidade de ser executado rapidamente na primeira tentativa.

Mike Crawford
fonte
1

meu remédio é começar obtendo respostas claras para duas perguntas:

  1. como medir o desempenho (por exemplo, medir o tempo de carregamento de dados )
  2. qual é o valor alvo (por exemplo, dados carregam em 3 segundos ou menos com 95% de confiança )

Aprendeu o truque acima com os caras da equipe tigre que já foram convidados a salvar uma versão quebrada do nosso produto. Esse lançamento foi interrompido por razões de desempenho, poderia fazer com que a empresa perdesse clientes estratégicos, o que justificava o envolvimento dos caras do tigre (btw muito caro). Fui designado para ajudá-los a esclarecer os detalhes do projeto; também usou isso como uma oportunidade de aprender um pouco ou dois sobre desempenho.

mosquito
fonte
1

O que eu descobri é o melhor antídoto para a otimização prematura desse método .

Depois de usá-lo para acelerar algum código (como neste exemplo ), ele se torna um vício próprio e você entende que o primeiro princípio de ajuste de desempenho não é ajustar o código, está encontrando o problema .

A otimização real é a otimização prematura, pois caçar para alimentar sua família é atirar latas. É tudo sobre encontrar a pedreira.

Mike Dunlavey
fonte
1
E, infelizmente, você só pode carregar 200 libras de volta para sua família, por isso não atire em esquilos o dia todo.
Jordânia
1

Pergunta antiga, mas vou oferecer esta resposta que difere consideravelmente das demais.

As grandes oportunidades para ganhos de desempenho vêm do processamento paralelo. Tente criar seu código para tirar proveito de vários threads. (Mesmo que, por simplicidade, você não faça isso na versão 1). Pouca adivinhação ou intuição necessária.

Qualquer outra coisa é otimização prematura e requer sua intuição, que geralmente está errada.

user949300
fonte
Ponto realmente bom. No passado, você podia contar com os processadores ficando muito mais rápidos a cada poucos anos. Agora você deve esperar apenas que haverá mais processadores.
precisa saber é o seguinte
0

Sua intuição pode melhorar com o tempo. Eu diria isso, talvez um pouco controverso, mas ao longo de muitos anos usando o VTune e o CodeAnalyst e agora o CodeXL, eu diria que sou muito mais preciso em minhas intuições do que antes sobre onde os pontos de acesso estarão, pelo menos para o ponto em que não sou mais pego de surpresa quando perfil algum código. Isso não significa que eu tente otimizar as coisas cegamente.

Na verdade, o perfil aumentou minha dependência de criadores de perfil, não a diminuiu. Estou apenas dizendo que posso antecipar com mais facilidade quais serão os resultados de criação de perfis em certa medida e além disso, eliminar com êxito pontos de acesso e melhorar o tempo necessário para concluir a operação de usuário final sem fazer facadas cegas no escuro e em falta (algo que você pode ser feito mesmo ao usar um criador de perfil até você começar a entender não apenas quais são os pontos ativos, mas por que exatamente eles são pontos ativos em relação a, digamos, falhas de cache).

No entanto, foi só quando comecei a usar os criadores de perfil que comecei a melhorar essa intuição. Um dos motivos é que, se você conhece bem seu código, seus palpites podem estar corretos em relação aos pontos de acesso maiores e mais óbvios, mas não a todas as sutilezas intermediárias. Naturalmente, se você tem uma operação de final de usuário que leva uma hora para concluir e existe um algoritmo de complexidade quadrática aberto que processa uma entrada que abrange cem mil elementos, provavelmente você pode sair rico apostando suas economias inteiras na ideia de que é a complexidade quadrática algoritmo com falha aqui. Mas isso não fornece informações detalhadas ou, por exemplo, informa exatamente o que não está contribuindo para o tempo.

Há tanto valor quando você começa a criar perfis e a ver onde todas as coisas que você pensou que poderiam ter contribuído mais para o tempo não estavam contribuindo por muito tempo; não as óbvias fontes óbvias de ineficiências, mas as que você suspeitava que poderiam ter sido um pouco ineficientes, mas, após o perfil, percebendo que elas mal contribuíam a qualquer momento. E é potencialmente aí que você obtém a percepção mais intuitiva de se mostrar errado em todas as áreas sutis em que não é óbvio exatamente quanto tempo está sendo gasto.

A intuição humana além da óbvia complexidade algorítmica geralmente começa incorreta, porque o que é eficiente para a máquina e o que é eficiente para a mente humana são muito diferentes. No início, não é tão intuitivo pensar em hierarquias de memória que vão dos registradores ao cache da CPU, à DRAM e ao disco. Não é intuitivo pensar que a aritmética redundante pode ser mais rápida do que fazer mais acessos de ramificação ou memória de uma tabela de consulta para ignorar algum trabalho de processamento. Tendemos a pensar em termos de quanto trabalho há para fazer, descontando coisas como o custo de tomar decisões e cargas e lojas de memória. O que é eficiente para o hardware geralmente é muito contra-intuitivo, de maneira a quebrar todas as suas suposições humanas começando,

Onde melhorar essa intuição pode ajudar, por meio de criação de perfil, é o design de interface . Os designs de interface são muito caros para mudar em retrospectiva, com os custos aumentando proporcionalmente ao número de lugares, dependendo dessa interface. Quando você começa a melhorar sua intuição, pode começar a projetar interfaces melhor da primeira vez, de maneira a deixar espaço para otimização futura sem alterações dispendiosas no projeto. Mais uma vez, porém, essa intuição é algo que você geralmente desenvolve e continua a desenvolver indefinidamente, sempre tendo esse perfilador em mãos.


fonte
0

Os criadores de perfil ajudam a corrigir a má intuição quando se trata de código. Dada a quantidade de hardware prevista atualmente, não é humanamente prático prever o desempenho do seu código, mas isso ainda era verdade no tempo de Knuth há muitas décadas atrás, que defendia que os criadores de perfil deveriam ser incluídos como parte das ferramentas padrão de desenvolvimento para corrigir o problema. natureza tola dos desenvolvedores. Mas eu vou seguir uma rota muito diferente com essa resposta, considerando a abrangência das respostas em outros aspectos e dizer que o entendimento do usuário final é a outra "solução".

Testemunhei, em minha experiência pessoal, um desenvolvedor particularmente brilhante (mas com pontos cegos sobre como os usuários realmente usam o software) otimizando um algoritmo de subdivisão com o criador de perfil em mãos (muito bom, caro e abrangente: o VTune da Intel com gráfico de chamadas amostragem na parte superior dos geradores de perfil da GPU) para malhas obtém resultados surpreendentes com bilhões de facetas na GPU ao subdividir primitivas simples como cubos com 6 polígonos de gaiola / entrada. Exceto que ele sintonizou e ajustou esse caso de teste que era diferente de qualquer caso de uso do mundo real (os usuários não querem um bilhão de facetas em um cubo subdividido começando a se parecer com uma esfera perfeita, suas entradas de subdivisão tendem a ser coisas como personagens e veículos e outras entradas complexas).

Curiosamente, fiquei mais longe com um cérebro tão funcional quanto ele e sem doutorado em minha carreira, pelo simples motivo de entender o que os usuários queriam, o que o marketing queria, o que os designers queriam. Eu não posso enfatizar o suficiente o quão útil é ser capaz de se colocar na mentalidade e nos sapatos do usuário e olhar para o seu software e o que ele precisa fazer como seus usuários reais, enquanto se esforça para se divorciar dos esforços que você coloca para construir o que você construiu e olhar para ele com um novo par de olhos. Eu até descobri pelo desenvolvedor acima que isso é algo impossível de fazer; ele achava que eu era culpado de ter um tipo de ego semelhante ao de todos os desenvolvedores tecnicamente esclarecidos, mas esquecidos pelo usuário, e eu sempre provei que ele estava errado quando usuários e designers corriam para mim para falar exatamente sobre o que fazer. Isso soa muito egoísta, mas vou equilibrar isso com o aviso de que não sou um programador tão brilhante, mas entendo o que os usuários e designers querem e isso me tornou particularmente favorecido no meu campo, onde isso parecia ser particularmente raro. qualidade por algum motivo. Como programadores, provavelmente estamos mais acostumados a testar testes do que entender e socializar com pessoas comuns, não técnicas.

Portanto, há criação de perfil e medição adequada, mas também há a necessidade fundamental de garantir que você esteja medindo uma operação com o tipo de entradas que os usuários do mundo real realmente fornecerão ao aplicativo. Caso contrário, você pode até ter o VTune ou CodeAnalyst ou gprof ou qualquer outro gerador de perfil em mãos e, ao mesmo tempo, tentar otimizar pontos de acesso contra o que pode parecer um caso de teste normal para o desenvolvedor, mas obscuro para os usuários, acabando pessimizando o caso de uso comum a favor de um caso de uso obscuro que poucos usuários, se houver, consideram aplicar.

No final do dia, todas as impraticabilidades que tendemos a levar, uma vez que os desenvolvedores podem ser equilibrados contra o martelo de ferro daquilo que torna os usuários genuinamente felizes o suficiente sem resolver a fome no mundo, e a necessidade prática de obter dinheiro para que possamos pagar aluguel, comprar cerveja ou olhe para mulheres nuas ou o que você quiser / precisar fazer. Tudo o que existe é potencialmente trabalhar contra essa necessidade fundamental dos negócios, e qualquer desenvolvedor tão nobre, tão heróico, para esquecer que se trata de ganhar dinheiro e, finalmente, satisfazer os usuários para que eles paguem pode fazer bem em se tornar realidade. e desative o modo deus, criando mundos virtuais em favor do mundo real, basta enviar e receber algum dinheiro para comida. Podemos nos perder nas métricas e práticas de software, mas fundamentalmente

Dragon Energy
fonte