otimização da condição da instrução if
-
09-06-2019 - |
Pergunta
Eu tenho uma instrução if com duas condições (separadas por um operador OR), uma das condições cobre +70% das situações e leva muito menos tempo para processar/executar do que a segunda condição, portanto, no interesse da velocidade, eu só quero o segunda condição a ser processada se a primeira condição for avaliada como falsa.
se eu ordenar as condições para que a primeira condição (a mais rápida) apareça primeiro na instrução if - nas ocasiões em que essa condição é atendida e avaliada como verdadeira, a segunda condição é processada?
if ( (condition1) | (condition2) ){
// do this
}
ou eu precisaria aninhar duas instruções if para verificar apenas a segunda condição se a primeira for avaliada como falsa?
if (condition1){
// do this
}else if (condition2){
// do this
}
Estou trabalhando em PHP, no entanto, presumo que isso possa ser independente de linguagem.
Solução
Para C, C++, C#, Java e outras linguagens .NET, as expressões booleanas são otimizadas para que, assim que o suficiente for conhecido, nada mais seja avaliado.
Um truque antigo para criar código ofuscado era usar isso para criar instruções if, como:
a || b();
se "a" for verdadeiro, "b()" nunca seria avaliado, então podemos reescrevê-lo em:
if(!a)
b();
e da mesma forma:
a && b();
se tornaria
if(a)
b();
Observe que isso é válido apenas para o || e && operador.Os dois operadores | & & é bit -in ou, e, e, respectivamente, e, portanto, não são "otimizados".
EDITAR:Conforme mencionado por outros, tentar otimizar o código usando lógica de curto-circuito raramente é um tempo bem gasto.
Primeiro busque clareza, porque é mais fácil de ler e entender.Além disso, se você tentar ser muito inteligente, uma simples reordenação dos termos poderá levar a um comportamento totalmente diferente, sem qualquer razão aparente.
Em segundo lugar, busque a otimização, mas somente após o timing e o perfil.Muitos desenvolvedores fazem otimização prematura sem criação de perfil.Na maioria das vezes é completamente inútil.
Outras dicas
Praticamente todas as linguagens fazem uma avaliação de curto-circuito.Significa que a segunda condição só é avaliada se for absolutamente necessária.Para que isso funcione, a maioria das linguagens usa o canal duplo, ||, e não o único, |.
Em C, C++ e Java, a instrução:
if (condition1 | condition2) {
...
}
avaliará ambas as condições sempre e só será verdadeira se toda a expressão for verdadeira.
A declaração:
if (condition1 || condition2) {
...
}
avaliará condition2
somente se condition1
é falso.A diferença é significativa se condição2 for uma função ou outra expressão com efeito colateral.
Não há, no entanto, nenhuma diferença entre o ||
caso e o if
/else
caso.
Tenho visto muitos desses tipos de perguntas ultimamente - otimização ao enésimo grau.
Acho que faz sentido em certas circunstâncias:
- A condição de cálculo 2 não é uma operação de tempo constante
- Você está perguntando estritamente para fins educacionais - você quer saber como o idioma funciona, não para salvar 3us.
Em outros casos, preocupar-se com a maneira “mais rápida” de iterar ou verificar uma condicional é bobagem.Em vez de escrever testes que exigem milhões de tentativas para ver qualquer diferença registrável (mas insignificante), concentre-se na clareza.
Quando outra pessoa (pode ser você!) pegar esse código em um mês ou um ano, o mais importante será a clareza.
Neste caso, o seu primeiro exemplo é mais curto, mais claro e não exige que você se repita.
De acordo com Este artigo O PHP faz avaliação de curto-circuito, o que significa que se a primeira condição for atendida, a segunda nem será avaliada.Também é muito fácil testar (do artigo):
<?php
/* ch06ex07 – shows no output because of short circuit evaluation */
if (true || $intVal = 5) // short circuits after true
{
echo $intVal; // will be empty because the assignment never took place
}
?>
O curto-circuito não é para otimização.Seu objetivo principal é evitar chamar código que não funcionará, mas que resultará em um teste legível.Exemplo:
if (i < array.size() && array[i]==foo) ...
Observe que array[i] pode muito bem obter uma violação de acesso se i estiver fora do alcance e travar o programa.Portanto este programa depende certamente de curto-circuitar a avaliação!
Acredito que esta seja a razão para escrever expressões desta forma com muito mais frequência do que preocupações de otimização.
Embora o uso de curto-circuito para fins de otimização seja muitas vezes um exagero, certamente existem outras razões convincentes para usá-lo.Um exemplo (em C++) é o seguinte:
if( pObj != NULL && *pObj == "username" ) {
// Do something...
}
Aqui, o curto-circuito é utilizado para garantir que pObj
foi alocado antes de desreferencia-lo.Isso é muito mais conciso do que aninhar if
declarações.
Como isso é marcado como independente de idioma, vou intervir.Pelo menos para Perl, a primeira opção é suficiente, não estou familiarizado com PHP.Ele avalia da esquerda para a direita e desaparece assim que a condição é atendida.
Na maioria dos idiomas com otimização decente, o primeiro funcionará perfeitamente.
O |
é um operador bit a bit em PHP.Isso não significa $a OR $b
, exatamente.Você vai querer usar o tubo duplo.E sim, como mencionado, o PHP faz avaliação de curto-circuito.De maneira semelhante, se a primeira condição de um &&
cláusula é avaliada como falsa, o PHP também não avalia o restante da cláusula.
VB.net tem duas expressões maravilhosas chamadas "OrElse" e "AndAlso"
OrElse entrará em curto-circuito na primeira vez que atingir uma avaliação True e executará o código desejado.
If FirstName = "Luke" OrElse FirstName = "Darth" Then
Console.Writeline "Greetings Exalted One!"
End If
AndAlso entrará em curto-circuito na primeira vez que fizer uma avaliação False e não avaliará o código dentro do bloco.
If FirstName = "Luke" AndAlso LastName = "Skywalker" Then
Console.Writeline "You are the one and only."
End If
Acho ambos úteis.