otimização de loops
-
29-09-2020 - |
Pergunta
Isenção de responsabilidade:Eu não sou um compilador especialista.Eu sou apenas curioso e vêm buscando a iluminação.
Eu tenho visto pessoas afirmam que -- para a eficiência -- for
loops, geralmente, devem usar um zero de comparação para o término do contrato.Assim, em vez de:
void blink1(int n) {
for (int i=0; i<n; i++) {
blink_led();
}
}
você deve escrever:
void blink2(int n) {
for (int i=n; i>0; i--) {
blink_led();
}
}
Eu pensei que era um pouco bobo:por que colocar o peso sobre o ser humano se um compilador poderia interpretar ambos os casos como "blink_led() n vezes"?
Mas usando O sr.Godbolt do Compilador Explorer, Agora eu acho que eu estou errado.Para todos os compiladores que eu tentei, o "compare contra zero" sempre produziram um curto circuito.Por exemplo, x86-64 gcc 10.2-O3 otimização produziu o seguinte presilhas internas:
blink1:
...
.L3:
xor eax, eax
add ebx, 1
call blink_led
cmp ebp, ebx
jne .L3
vs
blink2:
...
.L12:
xor eax, eax
call blink_led
sub ebx, 1
jne .L12
Portanto, eis a questão
Isso parece como um caso comum.
Por que não pode (ou não) o compilador notar que o efeito do for
loop é simplesmente "fazer isso" N "vezes" -- se a contagem ou a contagem regressiva -- e otimizar para que?
Solução
O que você lê é absurdo total, exceto para o mais primitivo dos compiladores.Primeiro, a comparação com um número inteiro é tão rápido, possivelmente, até mesmo mais rápido do que a comparação com uma constante.Em segundo lugar, uma boa optimização do compilador vai demorar um loop escrito usando algum padrão comum e transformá-lo no melhor código possível;ele pode não reconhecer a sua ofuscado padrão e produzir menos código para ele.
E por último, você não deve substituir legível com um código ilegível, a menos que haja uma necessidade real para ele.Se você passar uma hora fazendo a mudança, a produção de 20 horas salvo o tempo de CPU pelo menos.Quando você está naquele nível, melhor algoritmos são muito propensos a dar o melhor de poupança.
Outras dicas
Eu acho que concordo principalmente com o @gnasher729, mas aquelas pessoas que se preocupar com a "eficiência" critica usando o loop for em tudo -- o "eu" variável não adiciona nada ...
Por que não:
void blink3(int n) {
while (n-- > 0) {
blink_led();
}
}
Eu adicionei o "> 0" para um par de razões:1) apenas no caso de alguém que pede para um valor NEGATIVO de piscar, não quero andar para trás para 2 bilhões de vezes.2) é um pouco mais evidente para o unitiated (talvez).
Pelo caminho, no exemplo imaginário, o "blink_led()" função é estranho e suspeito -- provavelmente vai esperar para ser capaz de vê-lo ir, em seguida, desligado.Assim, a "eficiência" é um pouco fora da mesa.
Mas, em geral, para a maioria das coisas, a eficiência é principalmente sobre o quão rápido ele pode ser codificado e também (o mais importante) o quão rápido ele é compreendido.