O que os programadores "otimizam" de maneira atual? [fechadas]

14

Nos "bons e velhos tempos", quando copiávamos o shareware em disquetes para amigos, também usamos bastante montagem. Havia uma prática comum de "micro-otimização", em que você encarava e olhava as linhas de montagem até descobrir uma maneira de expressá-la com menos instruções. Havia até um ditado, matematicamente impossível, de que " Você sempre pode remover mais uma instrução " . Dado que alterar o desempenho do tempo de execução por pequenos fatores constantes não é um problema importante para a maioria da programação de hoje, os programadores estão transferindo esses micro- esforços de otimização em outro lugar?

Em outras palavras, uma prática recomendada pode ser levada a um estado extremo, onde não está mais agregando nada de valor? E está perdendo tempo?

Por exemplo: os programadores perdem tempo generalizando métodos privados que são chamados apenas de um local? O tempo é desperdiçado reduzindo os dados do caso de teste? Os programadores (ainda) estão preocupados demais com a redução de linhas de código?

Existem dois grandes exemplos do que estou procurando abaixo: (1) gastar tempo encontrando os nomes de variáveis ​​corretos e até renomeando tudo; e (2) Remoção de duplicação ainda menor e tênue de código.


Observe que isso é diferente da pergunta " Para o que você otimiza? ", Porque estou perguntando o que outros programadores parecem maximizar, com o estigma de serem "micro" otimizações e, portanto, não um uso produtivo do tempo.

Macneil
fonte
@ Macneil, não sei para que outros programadores otimizam, mas não tenho muito tempo para isso. Meus colegas de trabalho também estão ocupados (apenas meus 2 centavos).
Job
@Job: Você nunca viu alguém desperdiçando seu tempo, mudando o código sem motivo? Considere-se com sorte. Existem dois grandes exemplos abaixo: Nomes de variáveis ​​e duplicação de código menor.
Macneil
1
A questão, como está atualmente escrita, é uma melhoria. Não consigo remover a votação apertada, mas ela desaparecerá em alguns dias. Na verdade, a questão está atraindo algumas boas respostas.
Robert Harvey
1
Aliás, qualquer prática recomendada pode ser levada a tal extremo que não produza mais valor.
Robert Harvey

Respostas:

22

Formatação de código

Don't     get    me   wrong             ,
code      should be   consistent        & 
readable                                , 
but       some   take it         too far.
JeffO
fonte
Ah, sim, os bons e antigos tipos de variáveis ​​e nomes de variáveis ​​precisam de suas próprias colunas em uma série de declarações de variáveis. Oh! Esqueceu a linha extra para o =e o quarto para os inicializadores!
Macneil
[Droga, voto a favor, mas meu limite diário é atingido ...]
Macneil 28/11
3
Nossos professores nos forçaram a formatar o código para nossas atribuições dessa maneira. Levei anos para me livrar desse hábito.
Oliver Weiler
Oh céus. Em outras respostas eu estava rindo, mas esta realmente dói :-(
Steve314
2
+1 Uma vez eu trabalhei com uma biblioteca onde o desenvolvedor se recusou a fazer o seu código de const-correto, pois ele asneira seu código formatado em coluna ...
Dean Harding
20

Eu costumava escrever um monte de montador naquela época. Não é apenas que os compiladores melhoraram, é que a maioria dos hardwares agora tem muita lógica dedicada à execução de código fora de ordem. O verdadeiro problema micro é o agendamento, a maioria das instruções do computador leva vários relógios da máquina para produzir um resultado - e uma carga de memória que perde o cache pode levar várias centenas! Portanto, a idéia era agendar outras instruções para fazer algo útil, em vez de esperar por um resultado. E máquinas modernas podem emitir várias instruções por período de relógio. Depois que começamos a obter o HW de execução fora de ordem, descobri que tentar obter um ótimo desempenho com a codificação manual se tornou um jogo de canecas. Primeiro, o HW fora de ordem não executaria as instruções em seu pedido cuidadosamente criado, a nova e sofisticada arquitetura HW reduziu a penalidade de agendamento de software inadequado o suficiente para que o compilador estivesse geralmente dentro de alguns por cento do seu desempenho. Também descobri que os compiladores agora estavam implementando truques conhecidos, mas geradores de complexidade, como desenrolamento, carregamento inferior, pipelining de software etc. A linha inferior, você precisa trabalhar muito, pule alguns desses truques e o compilador o vence. Use todos eles e o número de instruções de montagem que você precisa aumentar várias vezes!

Provavelmente ainda mais importante, a maioria dos problemas de desempenho, não se refere às taxas de emissão de instruções, mas à inserção dos dados na CPU. Como mencionei acima, a latência da memória agora é de centenas de ciclos e a CPU pode executar várias instruções por período de clock, portanto, a menos que o programa - e especialmente as estruturas de dados sejam projetadas para que a taxa de acertos do cache seja extremamente alta, com o microtuning na instrução nível não terá retorno. Assim como os militares dizem que os amadores falam sobre táticas, os profissionais falam sobre logística. Agora, a programação de desempenho é mais de 90% da logística (movimentação de dados). E isso é difícil de quantificar, pois o gerenciamento de memória moderno normalmente possui vários níveis de cache e as páginas de memória virtual são gerenciadas por uma unidade de hardware chamada TLB. Também o alinhamento de endereços de baixo nível se torna importante, pois as transferências de dados reais não estão em unidades de bytes, ou até 64 bits, mas eles vêm em unidades de linhas de cache. Em seguida, a maioria das máquinas modernas possui hardware que tenta prever quais linhas de cache faltam em um futuro próximo e emitir pré-buscas automáticas para colocá-las no cache. Portanto, a realidade é que, com os modernos modelos de desempenho das CPUs, são tão complexos que quase não podem ser compreendidos. Mesmo simuladores de hardware detalhados nunca podem corresponder à lógica exata dos chips, portanto, o ajuste exato é simplesmente impossível.

Ainda há espaço para algumas codificações manuais. As bibliotecas de matemática (como a função exp), assim como as operações mais importantes de álgebra linear (como a multiplicação de matrizes), ainda são geralmente codificadas manualmente por especialistas que trabalham para o fornecedor de hardware (por exemplo, Intel ou AMD ou IBM), mas provavelmente apenas precisa de alguns programadores de assembler de alto nível por mega-computador corporativo.

Omega Centauri
fonte
1
A codificação manual está ficando cada vez mais difícil para as pessoas que trabalham fora dos fornecedores de CPU, pois a tarefa depende cada vez mais do conhecimento interno e das ferramentas específicas do fornecedor (compiladores e criadores de perfil). spiral.net tenta modelar a otimização da CPU e automatizar a busca por soluções ideais.
Rwong
Muitas linguagens de computador pressionam os programadores a otimizar de maneira insensata, tornando difícil o uso de precisão dupla para cálculos cujos resultados serão renderizados float. Por alguma razão que não consigo entender, muitas pessoas pensam que isso é uma coisa boa.
Supercat
10

Às vezes, gasto (desperdício?) Tempo ao escolher um bom nome para uma variável ou método, para que não seja apenas precisamente descritivo, mas também tenha um bom estilo linguístico.

Vai um pouco mais longe quando tento colocar todos os trabalhos (um programa) no mesmo estilo linguístico. Às vezes, minha opinião muda e eu reviso o livro. :)

Não, isso leva muito tempo. É bastante raro. Mas eu gosto de manter a boa gramática em meus programas.


fonte
3
Nomear é difícil. Portanto, você deve refatorar um nome quando pensar em um nome muito melhor. Observe que isso captura o esforço da mente e, esperançosamente, cristaliza o "porquê" também.
1
Isso é uma coisa do cérebro esquerdo (o lado esquerdo do seu cérebro é responsável pelo processamento da linguagem). Como programador de cérebro direito, costumo gastar muito menos tempo me preocupando com a semântica e mais tempo com a forma como todas as peças se encaixam.
Jason Baker
7
A nomeação de variáveis ​​e métodos é uma parte importante da manutenção. Um deve gastar tempo pensando sobre nomes, de modo que 5 anos a partir de agora, a pessoa mantendo o código tem um tempo mais fácil com ele.
GrandmasterB
@ Grandmaster: Não poderia concordar mais.
Robert Harvey
4
@ Cérebros direito: codifique para os esquerdistas, para que eu também possa ler seu código #
Juan Mendes
10

Complexidade do tempo. Eu gasto muito tempo otimizando as coisas para obter o pior desempenho possível em uma escala que é uma ordem de magnitude maior do que qualquer coisa que eu saiba que o programa encontrará realisticamente.

Eu sou obsessivo demais para deixar de lado o osso 'mas poderia crescer muito', mesmo quando outras decisões de design impedem que isso aconteça realisticamente.

No entanto, em minha defesa, se o irrealista se tornar realidade ... a otimização realmente não é mais 'micro'. Note, eu não disse impossível , mas irrealista .

Obviamente, os requisitos têm precedência.

Tim Post
fonte
1
Eu trabalhei para uma empresa que afundou por causa disso.
Henry
2
@Henry - Eu prometo, não fui eu :)
Tim Post
1
@Henry: Quer dizer que eles desperdiçado tempo otimizando para as coisas que provavelmente nunca iria acontecer, ou eles não pensar em coisas que provavelmente iria "nunca" acontecem ... até que eles fizeram acontecer e já era tarde demais?
Dean Harding
2
@ Henry: Se uma empresa possui um produto altamente escalável e ainda afunda, a culpa é das vendas e do marketing (por não ter como alvo clientes de alto volume e não ter preços apropriados), não pelo desenvolvimento.
Rwong
1
A empresa gastou muito tempo projetando um sistema para milhões de usuários quando eles não tinham um usuário. Deve ter sido culpa de marketing. Sim, vamos culpar o marketing, esses caras são idiotas.
Henry
8

Acho que perdi semanas no tempo brincando com manipuladores de exceção Java.

É muito trabalho para código que falha duas ou três vezes por ano. Isso deve ser um aviso ou uma informação? Erro ou fatal? É realmente fatal se o processo for reiniciado em cinco minutos? É realmente um aviso se tudo ainda estiver no estado padrão?

Muita observação do umbigo e discussão sobre a natureza de um erro de IO. Se você não consegue ler um arquivo pela rede, é um erro de arquivo ou de rede? E assim por diante.

Em um ponto, substituí todas as strings de concat por, String.formatpara que o erro anual de arquivo não resulte em objetos extras na pilha. Isso foi um desperdício.

sal
fonte
3
Este é um trabalho importante. O preço da falha = sua mensagem de erro sendo exibida no WTF diário.
Steve314
7

Suponho que estou preocupado demais com os LOCs. Não tanto os próprios LOCs, mas o número de instruções e ainda mais o número de instruções duplicadas. Sou alérgico a duplicar código. Em geral, adoro refatorar, mas suponho que cerca de 50% do que faço não torne o código significativamente mais agradável.

back2dos
fonte
4
+1 em "Sou alérgico a duplicar código". Veja também minha resposta aqui: programmers.stackexchange.com/questions/14610/…
Macneil
Pensando nisso - eu tenho esse problema com loops que se referem a um ponto que Knuth fez a respeito do goto, e às vezes tendo que trocar um ciclo ou dois ou algum código duplicado para escrever código estruturado. I irá utilizar um goto em casos muito raros (mais comum = código gerado), mas a minha variação deste distúrbio é perder tempo se preocupar e brincando com um loop infinitamente tentando eliminar a ineficiência trivial ainda manter a leitura de código.
Steve314
5

Lendo um arquivo linha por linha, em vez de apenas ler a linha inteira em uma string e processar a string de uma só vez.

Claro, faz diferença na velocidade de execução, mas raramente vale as linhas extras de código. Isso torna o código muito menos sustentável e aumenta o tamanho do código.

Sim, isso provavelmente não faz sentido se o arquivo tiver 3 GB de tamanho, mas a maioria dos arquivos não é tão grande (pelo menos não aqueles com os quais estou trabalhando ;-)).

Oliver Weiler
fonte
3
Mesmo com 3 GB ou mais, uma máquina de 64 bits pode lidar com isso com memória virtual. Use um arquivo mapeado na memória e ele nem sequer lerá qualquer parte do arquivo até que seja necessário. Lembre-se, mesmo que seja micro-otimização no caso normal.
Steve314
3

Quando eu estava escrevendo a linguagem assembly, fazia sentido procurar por bytes e ciclos, mas isso foi há muito tempo e os compiladores percorreram um longo caminho desde então. Eu não tentaria otimizar manualmente um agora.

Da mesma forma, quando eu mudei para escrever em C, era muito fácil fazer um trabalho melhor do que os compiladores C, mas todos os anos a Borland, a Microsoft ou alguém lançavam um novo e melhorado que chutava o anterior pela sala. Comecei a prestar atenção ao código de montagem real que o compilador estava emitindo e, se não estivesse escrevendo algum código legal e rígido, desenrolando loops, movendo variáveis ​​para fora dos loops, etc.

Hoje em dia eu estou escrevendo em linguagens muito mais altas como Perl, Python e Ruby. Eu uso alguns dos truques do compilador na frente, como desenrolar o loop se fizer sentido, mover variáveis ​​estáticas para fora dos loops, etc., mas não me preocupo tanto com isso porque as CPUs são um pouquinho mais rápidas agora. Se um aplicativo parece arrastar inesperadamente, usarei um criador de perfil e verei o que posso encontrar; se algo puder ser aprimorado, começarei a fazer benchmarking de várias maneiras em que posso pensar em fazer algo mais rápido e depois ver como ele aumenta de escala.

Em geral, tento ser inteligente em como escrevo código, com base em anos de experiência.

o homem de lata
fonte
Olá Greg, obrigado pela resposta, mas estou procurando o que os programadores fazem para perder tempo, não para otimizar o desempenho do tempo de execução. Existem dois grandes exemplos acima: Nomes de variáveis ​​e remoção de duplicação de código ainda menor.
Macneil
3

Uma micro-otimização: aprimorando o desempenho de thread único de coisas que são paralelizáveis ​​ou que podem simplesmente ser melhoradas com o novo hardware.

Se algo está lento em um computador de 10 anos atrás, provavelmente uma solução mais barata é comprar um computador mais novo e mais rápido, em vez de desperdiçar a otimização do tempo do programador. Um grande foco das otimizações consideradas, no entanto, deve ser encontrar uma maneira de usar os 8 núcleos que você pode obter hoje ou os 64 que você poderá obter daqui a alguns anos, em vez de se agonizar com minúcias, como o custo extra do lixo coleção.

Kevin Cantu
fonte
2

A micro-otimização em termos de desempenho em tempo de execução dificilmente é um problema fechado até hoje (embora possa ser menos comum). Ocasionalmente, tenho que explicar às pessoas que a sobrecarga de alocar um objeto extra a cada solicitação ou adicionar uma chamada de função extra é insignificante.

Além disso, também vejo programadores otimizar para simplificar (inclusive eu). Ainda tenho que trabalhar em algum lugar que não precisei explicar a diferença entre simplicidade e simplismo.

Jason Baker
fonte
Por que programadores. ser diferente? Qual a diferença, por favor.
Dan Rosenstark
@Yar - Por que os programadores seriam diferentes do que?
Jason Baker
por que programmers.= programmers.stackexchange.comseria diferente de todos os lugares em que você trabalhou onde teve que explicar a diferença entre esses dois conceitos? Por favor, explique a diferença.
Dan Rosenstark
@ Yar - Eu não sei o que faria. De fato, como o objetivo do programmers.se é ajudar os programadores a reunir conhecimento, espero que não seja assim, para que as pessoas sejam pelo menos um pouco esclarecidas com a minha resposta.
Jason Baker
2
Então, qual é a diferença entre simplicidade e simplismo?
Dan Rosenstark 29/11
2

Sou a favor do princípio de não otimizar, a menos que seja realmente necessário. E sou a favor do princípio do primeiro perfil. E, em princípio, otimizarei apenas algo que fará a diferença necessária.

Isso é em princípio. Mas o princípio é um mentiroso.

Eu tenho o hábito de cuidar de funções em bibliotecas usadas com freqüência, que eu acho que serão muito usadas em loops internos. E então, quando você descobre algo em outra função, que não é tão frequentemente usado ...

Ah - e depois há a lógica "eu estou escrevendo - é claro que é uma biblioteca importante".

Ah - e entre. Eu nunca usei um criador de perfil para orientar uma otimização. Não tenha acesso a um comercial e nunca desenvolveu a motivação para descobrir o gprof.

Basicamente, sou hipócrita. Esses princípios se aplicam a outras pessoas, mas tenho muito medo de alguém dizer "mas por que você escreveu dessa maneira lenta e ruim?" para que eu nunca possa realmente aplicá-las adequadamente a mim mesmo.

Eu não sou tão ruim quanto aqui, no entanto. E eu sou completamente imune ao auto-engano, então você sabe que eu estou certo sobre isso!

EDITAR

Devo acrescentar - um dos meus maiores problemas estúpidos são as despesas gerais. Não em todos os lugares, é claro, mas naqueles casos que eu acho que será muito usado em loops internos (onde não tenho evidências objetivas de um problema). Escrevi códigos desagradáveis ​​baseados em offset para evitar fazer chamadas de método virtual mais de uma vez. O resultado pode até ser mais lento, pois provavelmente não é um estilo de codificação que os otimizadores sejam projetados para lidar bem - mas é mais inteligente ;-)

Steve314
fonte
+1 Ah, sim! Essa classe analisa os argumentos de linha de comando altamente específicos e peculiares do meu aplicativo, mas deixe-me formatá-lo e documentá-lo totalmente quando Javadoc, porque certamente outros o usarão por anos! [Será necessário upvote mais tarde, o meu boné diária é atingido.]
Macneil
@ Macneil - isso é Doxygen, eu vou saber. Com todas as opções que posso encontrar ativadas, todas as pequenas funções são "documentadas" em detalhes excrutadores, completas com uma dúzia de gráficos bonitos do GraphViz. Realmente ajuda a todos a apreciar a importância do meu código - e a impressão pode ser um papel de parede de um grande escritório.
Steve314
1

Nos velhos tempos, quando os computadores tinham tempos de relógio medidos em microssegundos, memória medida em kilobytes e compiladores primitivos, a micro otimização fazia algum sentido.

A velocidade e o tamanho dos computadores da geração atual e a qualidade dos compiladores da geração atual significam que a micro-otimização geralmente é uma perda total de tempo. As exceções tendem a ser quando você absolutamente precisa obter o desempenho máximo de algum código computacionalmente intensivo ... ou está escrevendo para um sistema incorporado com recursos extremamente limitados.

mas estou procurando o que os programadores fazem para perder tempo, não para otimizar o desempenho do tempo de execução.

O Twitter e o Facebook vêm à mente :-)

Stephen C
fonte
Olá Stephen, esse é um ótimo comentário sobre micro-otimização, mas você vê algum equivalente moderno? [Facebook e Twitter não são "melhores práticas" que podem ser realizadas muito longe.]
Macneil
Ainda faz sentido. Os tempos de relógio pode ser ordens de magnitude menor, mas o código é ordens de magnitude maior ...
hplbsh
@ Stuart - isso significa que há ordens de magnitude em mais código para otimizar ... que simplesmente não escalam.
Stephen C