Antes de tudo, entendo que em 90% dos aplicativos a diferença de desempenho é completamente irrelevante, mas só preciso saber qual é a construção mais rápida. Isso e ...
As informações atualmente disponíveis na rede são confusas. Muitas pessoas dizem que foreach é ruim, mas tecnicamente deve ser mais rápido, pois é suposto simplificar a gravação de uma passagem de array usando iteradores. Iteradores, que novamente são mais rápidos, mas no PHP também são aparentemente muito lentos (ou isso não é algo do PHP?). Eu estou falando sobre as funções da matriz: next () prev () reset () etc., bem, se elas são funções pares e não um daqueles recursos da linguagem PHP que se parecem com funções.
Para restringir um pouco isso : não sou interessante em percorrer matrizes em etapas com nada mais que 1 (nenhuma etapa negativa também, isto é, iteração reversa). Também não estou interessado em uma travessia de e para pontos arbitrários, apenas 0 no comprimento. Também não vejo manipular matrizes com mais de 1000 chaves acontecendo regularmente, mas vejo uma matriz sendo percorrida várias vezes na lógica de um aplicativo! Também quanto às operações, em grande parte apenas manipulação e eco de cordas.
Aqui estão alguns sites de referência:
http://www.phpbench.com/
http://www.php.lt/benchmark/phpbench.php
O que eu ouço em todos os lugares:
foreach
é lento e, portanto,for
/while
é mais rápido- PHPs
foreach
copia a matriz que itera; para torná-lo mais rápido, você precisa usar referências - código como este: é mais rápido que um
$key = array_keys($aHash); $size = sizeOf($key);
for ($i=0; $i < $size; $i++)foreach
Aqui está o meu problema. Eu escrevi este script de teste: http://pastebin.com/1ZgK07US e não importa quantas vezes eu execute o script, recebo algo assim:
foreach 1.1438131332397
foreach (using reference) 1.2919359207153
for 1.4262869358063
foreach (hash table) 1.5696921348572
for (hash table) 2.4778981208801
Em resumo:
foreach
é mais rápido do queforeach
com referênciaforeach
é mais rápido quefor
foreach
é mais rápido do quefor
para uma tabela de hash
Alguém pode explicar?
- Estou fazendo algo errado?
- A coisa de referência do PHP foreach está realmente fazendo a diferença? Quero dizer, por que não copiá-lo se você passar por referência?
- Qual é o código do iterador equivalente para a instrução foreach; Já vi alguns na rede, mas cada vez que os teste, o tempo está muito longe; Também testei algumas construções simples de iteradores, mas nunca obtive resultados decentes - os iteradores de matriz no PHP são terríveis?
- Existem maneiras / métodos / construções mais rápidos para iterar por uma matriz diferente de FOR / FOREACH (e WHILE)?
Versão do PHP 5.3.0
Edit: Answer Com a ajuda de pessoas daqui, pude reunir as respostas para todas as perguntas. Vou resumir aqui:
- "Estou fazendo algo errado?" O consenso parece ser: sim, não posso usar eco em benchmarks. Pessoalmente, ainda não vejo como o eco é alguma função com tempo aleatório de execução ou como qualquer outra função é de alguma forma diferente - isso e a capacidade desse script de gerar apenas os mesmos resultados exatos do foreach melhor do que tudo é difícil para explicar, embora apenas "você esteja usando eco" (bem, o que eu deveria estar usando). No entanto, admito que o teste deve ser feito com algo melhor; embora um compromisso ideal não venha à mente.
- "O PHP para cada coisa de referência está realmente fazendo a diferença? Quero dizer, por que não copiá-lo se você passar por referência?" O ircmaxell mostra que sim, mais testes parecem provar na maioria dos casos que a referência deve ser mais rápida - embora, dado o meu trecho de código acima, definitivamente não signifique tudo. Eu aceito que o problema provavelmente não seja intuitivo demais para se preocupar com esse nível e exigiria algo extremo, como descompilar, para realmente determinar qual é o melhor para cada situação.
- "Qual é o código do iterador equivalente para a instrução foreach; eu vi alguns na rede, mas cada vez que os testo, o tempo está muito distante; eu também testei algumas construções simples do iterador, mas nunca obtive resultados decentes - os iteradores de array no PHP são péssimos? " a ircmaxell forneceu a resposta abaixo; embora o código possa ser válido apenas para a versão PHP> = 5
- "Existem maneiras / métodos / construções mais rápidos para iterar através de uma matriz diferente de FOR / FOREACH (e WHILE)?" Agradecemos a Gordon pela resposta. O uso de novos tipos de dados no PHP5 deve oferecer um aumento no desempenho ou na memória (um dos quais pode ser desejável dependendo da sua situação). Embora em termos de velocidade muitos dos novos tipos de array não pareçam melhores que array (), a fila de prioridade e o armazenamento de objetos de paródia parecem ser substancialmente mais rápidos. Link fornecido por Gordon: http://matthewturland.com/2010/05/20/new-spl-features-in-php-5-3/
Obrigado a todos que tentaram ajudar.
Provavelmente vou me ater ao foreach (a versão sem referência) para qualquer passagem simples.
Respostas:
Minha opinião pessoal é usar o que faz sentido no contexto. Pessoalmente, eu quase nunca uso
for
para atravessar array. Eu o uso para outros tipos de iteração, masforeach
é muito fácil ... A diferença de horário será mínima na maioria dos casos.A grande coisa a observar é:
Esse é um loop caro, pois as chamadas contam com todas as iterações. Contanto que você não esteja fazendo isso, não acho que realmente importe ...
Quanto à referência que faz a diferença, o PHP usa a cópia na gravação; portanto, se você não gravar na matriz, haverá relativamente pouca sobrecarga durante o loop. No entanto, se você começar a modificar a matriz dentro da matriz, é aí que começará a ver diferenças entre elas (já que será necessário copiar toda a matriz e a referência pode apenas modificar inline) ...
Quanto aos iteradores,
foreach
é equivalente a:Na medida em que existem maneiras mais rápidas de iterar, isso realmente depende do problema. Mas eu realmente preciso perguntar, por quê? Entendo que quero tornar as coisas mais eficientes, mas acho que você está desperdiçando seu tempo com uma micro-otimização. Lembre-se,
Premature Optimization Is The Root Of All Evil
...Edit: Com base no comentário, eu decidi fazer uma corrida rápida de benchmark ...
E os resultados:
Portanto, se você estiver modificando a matriz no loop, é várias vezes mais rápido usar referências ...
E a sobrecarga apenas para a referência é realmente menor do que copiar a matriz (isso é na 5.3.2) ... Então, parece (na 5.3.2 pelo menos) como se as referências fossem significativamente mais rápidas ...
fonte
"the better standard way to adopt."
desempenho do @srcspider não é o único critério para escolher o que adotar. especialmente em um caso tão exagerado. Sinceramente, você está apenas perdendo seu tempoNão tenho certeza se isso é tão surpreendente. A maioria das pessoas que codifica em PHP não é bem versada no que o PHP está realmente fazendo no bare metal. Vou declarar algumas coisas, que serão verdadeiras na maioria das vezes:
Se você não está modificando a variável, o valor é mais rápido no PHP. Isso ocorre porque a referência é contada de qualquer maneira e o valor por valor diminui o seu desempenho. Ele sabe que, no momento em que você modifica o ZVAL (estrutura de dados interna do PHP para a maioria dos tipos), ele deve ser interrompido de maneira direta (copie-o e esqueça o outro ZVAL). Mas você nunca a modifica, por isso não importa. As referências tornam isso mais complicado com mais escrituração contábil para saber o que fazer quando você modifica a variável. Portanto, se você é somente leitura, paradoxalmente, é melhor não apontar isso com o &. Eu sei, é contra-intuitivo, mas também é verdade.
Foreach não é lento. E para uma iteração simples, a condição em que está testando - "estou no final desta matriz" - é feita usando código nativo, não opcodes PHP. Mesmo que sejam opcodes em cache da APC, ainda é mais lento que um monte de operações nativas feitas no bare metal.
O uso de um loop for "for ($ i = 0; $ i <count ($ x); $ i ++) é lento devido ao count () e à falta da capacidade do PHP (ou realmente de qualquer linguagem interpretada) avaliar em análise tempo, se alguma coisa modifica a matriz, o que impede a avaliação da contagem uma vez.
Mas mesmo depois de corrigi-lo com "$ c = count ($ x); para ($ i = 0; $ i <$ c; $ i ++), o $ i <$ c é, na melhor das hipóteses, um monte de opcodes do Zend, como é o $ i ++. No curso de 100000 iterações, isso pode importar. O Foreach sabe no nível nativo o que fazer. Nenhum código de código PHP necessário para testar a condição "eu estou no final desta matriz".
E a velha escola "while (list (" stuff? Bem, usando each (), current (), etc.), todos envolverão pelo menos uma chamada de função, que não é lenta, mas não é gratuita. Sim, essas são opcodes PHP novamente! Portanto, enquanto + list + cada um também tem seus custos.
Por esses motivos, foreach é compreensivelmente a melhor opção para iteração simples.
E não se esqueça, também é o mais fácil de ler, por isso é ganha-ganha.
fonte
Uma coisa a ser observada nos benchmarks (especialmente o phpbench.com) é que, embora os números sejam bons, os testes não. Muitos dos testes realizados no phpbench.com são triviais e abusam da capacidade do PHP de armazenar em cache as pesquisas de array para distorcer os benchmarks ou, no caso de iterar sobre um array, na verdade, não é testado em casos reais (ninguém escreve vazio para rotações). Fiz meus próprios benchmarks que achei que refletem bastante os resultados do mundo real e sempre mostram a sintaxe iterativa nativa do idioma
foreach
saindo por cima (surpresa, surpresa).fonte
É 2020 e os materiais evoluíram bastante com o php 7.4 e o opcache .
Aqui está o benchmark OP ^, executado como CLI unix , sem as partes echo e html.
O teste foi executado localmente em um computador comum.
Script de benchmark modificado:
Resultado:
Como você pode ver, a evolução é insana, cerca de 560 vezes mais rápida do que a relatada em 2012.
Nas minhas máquinas e servidores, após minhas inúmeras experiências, o básico para loops é o mais rápido. Isso é ainda mais claro usando loops aninhados ( $ i $ j $ k ..)
É também o mais flexível no uso e tem uma melhor legibilidade do meu ponto de vista.
fonte
Penso, mas não tenho certeza: o
for
loop leva duas operações para verificar e incrementar valores.foreach
carrega os dados na memória e itera todos os valores.fonte