Pergunta

Se você tem o seguinte:

$var = 3; // we'll say it's set to 3 for this example
if ($var == 4) {
    // do something
} else if ($var == 5) {
    // do something
} else if ($var == 2) {
    // do something
} else if ($var == 3) {
    // do something
} else {
    // do something
}

Se digamos 80% da $var tempo é de 3, você se preocupar com o fato de que ele está passando por 4 se casos antes de encontrar o verdadeiro caso?

Estou pensando em um site pequeno não é um grande negócio, mas o que acontece quando essa declaração se vai correr 1000s de vezes por segundo?

Eu estou trabalhando em PHP, mas estou pensando a linguagem não importa.

Foi útil?

Solução

Aqui está como nós o fizemos quando eu costumava escrever software para sistemas de radar. (Speed ??importa no radar. É um dos poucos lugares onde "tempo real" na verdade significa "real" em vez de "fast".)

[Eu vou mudar para sintaxe Python, é mais fácil para mim e eu tenho certeza que você pode interpretá-lo.]

if var <= 3:
    if var == 2:
        # do something
    elif var == 3:
        # do something
    else: 
        raise Exception
else:
    if var == 4:
        # do something
    elif var == 5:
        # do something
    else:
        raise Exception

Seu se-declarações formar uma árvore em vez de uma lista simples. Como você adicionar condições a esta lista, você balançar ao redor do centro da árvore. A seqüência fixa de n comparações leva, em média, n / 2 etapas. As ligações de árvores para uma sequência de comparações que leva log ( n ) comparações.

Outras dicas

Bem, eu acredito que quase todo o tempo , a legibilidade de, digamos, ter valores numericamente ordenados iria substituir quaisquer benefícios minúsculos você pode ganhar através da redução do número de instruções de comparação.

Dito isto, como com todos os otimização:

  1. Faça-lhe o trabalho
  2. Meça-
  3. Se for rápido o suficiente, deixá-lo sozinho
  4. Se ele é muito lento, em seguida, otimizar it

Oh, e eu provavelmente usar um switch / case a partir do get-go! ; -)

Um caso clássico de isso acontecer (com literalmente 5 opções como em seu post) estava em ffmpeg, na função decode_cabac_residual. Este foi bastante importante, como profiling (muito importante - NÃO FAZEM otimizar antes profiling) mostrou contados para mais de 10-15% do tempo gasto na decodificação de vídeo H.264. A instrução if controlado um conjunto de instruções que foi calculado de forma diferente para os diversos tipos de resíduos a ser decodificado - e, infelizmente, muita velocidade foi perdido devido ao tamanho do código, se a função foi duplicado 5 vezes para cada um dos 5 tipos de residual. Então, ao invés, um if cadeia teve que ser usado.

Profiling foi feito em muitos teste comum córregos para ordená-las em termos de probabilidade; o topo era o mais comum, o inferior o mínimo. Isso deu um ganho de velocidade de pequeno porte.

Agora, em PHP, eu suspeito que há muito menos do ganho de velocidade estilo de baixo nível que você deseja obter em C, como no exemplo acima.

Usando uma instrução switch / case é o definitivamente o caminho a percorrer aqui.

Isto dá o compilador (intérprete) a possibilidade de utilizar uma mesa de salto para chegar ao ramo direito sem ter que fazer comparações N. Pense nisso a criação de uma matriz de endereços indexado como 0, 1, 2, .., então ele pode apenas olhar o correto-se na matriz em uma única operação.

Além disso, uma vez que o é sobrecarga menos sintática em um comunicado caso, ele lê mais fácil também.

Update: se as comparações são adequados para uma instrução switch, então esta é uma área onde perfil guiada otimizações podem ajudar. Ao executar uma compilação PGO com cargas de ensaio realistas o sistema pode gerar informações de uso ramo, e depois usar isso para otimizar o caminho tomado.

Ao invés de resposta a pergunta PHP, eu vou responder um pouco mais geral. Ela não se aplica diretamente para o PHP como ele irá passar por algum tipo de interpretação.

Muitos compiladores pode converter de e para se-elif-elif -... blocos para alternar blocos se necessário, e os testes nas elif-partes são suficientes simples (e no resto da semântica passa a ser compatível). Para 3-4 testes não há necessariamente nada a ganhar usando uma tabela de salto.

A razão é que o branch-preditor na CPU é realmente bom em prever o que acontece. Com efeito, a única coisa que acontece é um pouco maior pressão sobre buscar instrução, mas é dificilmente vai ser o mundo tremer.

No seu exemplo no entanto, a maioria dos compiladores reconheceria que $ var é uma constante 3 e, em seguida, substitua $ var com 3 na if..elif .. blocos. Este, por sua vez faz com que a constante expressões que eles são dobrados a qualquer verdadeiro ou falso. Todos os falsos ramos é morto pelo eliminador de-código morto eo teste verdadeiro é eliminado também. O que resta é o caso em que $ var == 3. Você não pode confiar em PHP sendo que, embora inteligente. Em geral, você não pode fazer a propagação de $ var, mas pode ser possível a partir de algumas chamadas de sites.

Você poderia tentar ter uma série de blocos de código, o que você põe em. Em seguida, todos os blocos de código têm o mesmo teto.

Perl 6:

our @code_blocks = (
  { 'Code Block 0' },
  { 'Code Block 1' },
  { 'Code Block 2' },
  { 'Code Block 3' },
  { 'Code Block 4' },
  { 'Code Block 5' },
);

if( 0 <= $var < @code_blocks.length ){
  @code_blocks[$var]->();
}

Se o código tem que fazer testes adicionais em seguida, ele certamente vai correr mais devagar. Se o desempenho é crítico nesta seção do código, em seguida, você deve colocar o caso mais comum (s) primeiro.

Eu normalmente concordar com a "medida, em seguida, otimizar" método quando você não tem certeza se o desempenho será rápido o suficiente, mas se o código simplesmente precisa correr tão rápido quanto possível e a correção é tão fácil como reorganizar o testes, então eu faria o código rápido agora e fazer alguma medição depois de ir ao vivo para garantir que sua suposição (por exemplo, de que 3 vai acontecer de 80% do tempo) é realmente correto.

Com código onde é puramente uma análise igualdade eu movê-lo para um switch / case, como que proporciona melhor desempenho.

$var = 3; // we'll say it's set to 3 for this example
switch($var)
 {
   case 4:
      //do something
      break;
   case 5:
      //do something
      break;
   case:
      //do something when none of the provided cases match (same as using an else{ after the elseif{
 }

Agora, se o seu fazer comparações mais complicado que eu seria ou ninho los no interruptor, ou simplesmente usar o elseif.

Em linguagens orientadas a objeto, se uma opção fornece ifs maciças, então isso significa que você deve apenas seguir o comportamento (por exemplo, seus blocos //do something) para o objeto contendo o valor.

Só você pode dizer se a diferença de otimizar a ordem, ou reorganizando-lo no efeito de desempenho ser uma árvore binária, iria fazer uma diferença significativa. Mas eu suspeito que você vai ter que ter milhões de vezes por segundo, não milhares, para incomodar mesmo pensando sobre isso em PHP (e mais ainda em algumas outras línguas).

Tempo lo. Veja quantas vezes um segundo você pode executar o acima if / else if / else com ausência de acção e US $ var não ser uma das escolhas.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top