Прежде всего, я понимаю, что в 90% приложений разница в производительности совершенно не имеет значения, но мне просто нужно знать, какая из них быстрее. Это и ...
Информация, доступная в настоящее время о них в сети, сбивает с толку. Многие люди говорят, что foreach - это плохо, но технически это должно быть быстрее, поскольку предполагается упростить написание массива с помощью итераторов. Итераторы, которые опять-таки должны быть более быстрыми, но в PHP, по-видимому, тоже очень медленные (или это не PHP)? Я говорю о функциях массива: next () prev () reset () и т. Д. Хорошо, если они являются даже функциями, а не одной из тех функций языка PHP, которые выглядят как функции.
Чтобы немного сузить это : я m не интересен для обхода массивов с шагами, превышающими 1 (отрицательных шагов тоже нет, т.е. обратная итерация). Я также не заинтересован в обходе и от произвольных точек, просто 0 к длине. Я также не вижу, что манипулирование массивами с более чем 1000 ключами происходит регулярно, но я вижу, что массив перебирается несколько раз в логике приложения! Также что касается операций, в основном только строковых манипуляций и эха.
Вот несколько справочных сайтов:
http://www.phpbench.com/
http://www.php.lt/benchmark /phpbench.php
What я слышу везде:
foreach
медленный, и, таким образом, для
/ , в то время как
быстрее foreach
копирует массив, по которому он повторяется; чтобы сделать это быстрее, вам нужно использовать код ссылки $ key = array_keys ($ aHash); $ size = sizeOf ($ key);
для ($ i = 0; $ i быстрее, чем foreach
Вот моя проблема. Я написал этот тестовый скрипт: http://pastebin.com/1ZgK07US и независимо от того, сколько раз я запускаю скрипт, я получаю что-то вроде этого:
foreach 1.1438131332397
foreach (using reference) 1.2919359207153
for 1.4262869358063
foreach (hash table) 1.5696921348572
for (hash table) 2.4778981208801
Короче:
foreach
быстрее, чем foreach
со ссылкой , foreach
быстрее, чем для
, foreach
быстрее, чем для
для хеш-таблицы Может кто-нибудь объяснить?
PHP версии 5.3.0
С помощью людей здесь я смог собрать воедино ответы на все вопросы. Я суммирую их здесь:
Спасибо всем, кто пытался помочь.
Я, скорее всего, буду придерживаться foreach (нереферентная версия) для любого простого обхода.
Мое личное мнение - использовать то, что имеет смысл в контексте. Лично я почти никогда не использую вместо
для обхода массива. Я использую его для других типов итераций, но foreach
слишком прост ... Разница во времени в большинстве случаев будет минимальной.
Главное, на что следует обратить внимание:
for ($i = 0; $i < count($array); $i++) {
Это дорогой цикл, поскольку он вызывает счетчик на каждой итерации. Пока вы этого не делаете, я не думаю, что это действительно имеет значение ...
Что касается ссылки, имеющей значение, PHP использует копирование при записи, поэтому, если вы не записываете в массив , при зацикливании будет относительно мало накладных расходов. Однако, если вы начнете изменять массив внутри массива, вы начнете видеть различия между ними (так как нужно будет скопировать весь массив, а ссылка может просто изменить встроенный) ...
Что касается итераторы, foreach
эквивалентно:
$it->rewind();
while ($it->valid()) {
$key = $it->key(); // If using the $key => $value syntax
$value = $it->current();
// Contents of loop in here
$it->next();
}
Что касается более быстрых способов итерации, это действительно зависит от проблемы. Но мне действительно нужно спросить, почему? Я понимаю, что хочу сделать вещи более эффективными, но я думаю, что вы зря тратите время на микрооптимизацию. Помните, Преждевременная оптимизация - корень всего зла
...
Изменить: На основании комментария я решил провести быстрый тестовый прогон ...
$a = array();
for ($i = 0; $i < 10000; $i++) {
$a[] = $i;
}
$start = microtime(true);
foreach ($a as $k => $v) {
$a[$k] = $v + 1;
}
echo "Completed in ", microtime(true) - $start, " Seconds\n";
$start = microtime(true);
foreach ($a as $k => &$v) {
$v = $v + 1;
}
echo "Completed in ", microtime(true) - $start, " Seconds\n";
$start = microtime(true);
foreach ($a as $k => $v) {}
echo "Completed in ", microtime(true) - $start, " Seconds\n";
$start = microtime(true);
foreach ($a as $k => &$v) {}
echo "Completed in ", microtime(true) - $start, " Seconds\n";
И результаты:
Completed in 0.0073502063751221 Seconds
Completed in 0.0019769668579102 Seconds
Completed in 0.0011849403381348 Seconds
Completed in 0.00111985206604 Seconds
Итак, если вы изменяете массив в цикле, в несколько раз быстрее использовать ссылки ...
И накладные расходы только на ссылку на самом деле меньше, чем при копировании массива (это в 5.3.2) ... Получается (по крайней мере, в версии 5.3.2), что ссылки значительно быстрее ...
Одна вещь, на которую следует обратить внимание в тестах (особенно на phpbench.com): даже если цифры верны, тесты - нет. Многие тесты на phpbench.com выполняют тривиальные задачи и злоупотребляют способностью PHP кэшировать поиск по массиву для искажения результатов тестов или в случае итерации по массиву фактически не тестируют его в реальных случаях (никто не пишет пустые для циклов). Я провел свои собственные тесты, которые, как я обнаружил, в значительной степени отражают результаты реального мира, и они всегда показывают собственный итерационный синтаксис языка foreach
, выходящий на первое место (сюрприз, сюрприз ).
//make a nicely random array
$aHash1 = range( 0, 999999 );
$aHash2 = range( 0, 999999 );
shuffle( $aHash1 );
shuffle( $aHash2 );
$aHash = array_combine( $aHash1, $aHash2 );
$start1 = microtime(true);
foreach($aHash as $key=>$val) $aHash[$key]++;
$end1 = microtime(true);
$start2 = microtime(true);
while(list($key) = each($aHash)) $aHash[$key]++;
$end2 = microtime(true);
$start3 = microtime(true);
$key = array_keys($aHash);
$size = sizeOf($key);
for ($i=0; $i<$size; $i++) $aHash[$key[$i]]++;
$end3 = microtime(true);
$start4 = microtime(true);
foreach($aHash as &$val) $val++;
$end4 = microtime(true);
echo "foreach ".($end1 - $start1)."\n"; //foreach 0.947947025299
echo "while ".($end2 - $start2)."\n"; //while 0.847212076187
echo "for ".($end3 - $start3)."\n"; //for 0.439476966858
echo "foreach ref ".($end4 - $start4)."\n"; //foreach ref 0.0886030197144
//For these tests we MUST do an array lookup,
//since that is normally the *point* of iteration
//i'm also calling noop on it so that PHP doesn't
//optimize out the loopup.
function noop( $value ) {}
//Create an array of increasing indexes, w/ random values
$bHash = range( 0, 999999 );
shuffle( $bHash );
$bstart1 = microtime(true);
for($i = 0; $i < 1000000; ++$i) noop( $bHash[$i] );
$bend1 = microtime(true);
$bstart2 = microtime(true);
$i = 0; while($i < 1000000) { noop( $bHash[$i] ); ++$i; }
$bend2 = microtime(true);
$bstart3 = microtime(true);
foreach( $bHash as $value ) { noop( $value ); }
$bend3 = microtime(true);
echo "for ".($bend1 - $bstart1)."\n"; //for 0.397135972977
echo "while ".($bend2 - $bstart2)."\n"; //while 0.364789962769
echo "foreach ".($bend3 - $bstart3)."\n"; //foreach 0.346374034882