Почему foreach такой медленный? - PullRequest
2 голосов
/ 10 марта 2010

PHPBench.com запускает быстрые тестовые сценарии для каждой загрузки страницы.В тесте foreach, когда я его загружаю, выполнение foreach занимает в 4-10 раз больше времени, чем в третьем примере.

Почему конструкция на родном языке, по-видимому, медленнее, чем выполнение логики самостоятельно?

Ответы [ 3 ]

9 голосов
/ 10 марта 2010

Может быть, это связано с тем, что foreach работает с копией массива?

Или, может быть, это связано с тем, что при цикле с foreach на каждой итерации указатель внутреннего массива изменяется, чтобы указывать на следующий элемент?

Цитирование соответствующей части справочной страницы foreach :

Примечание. Если на массив не ссылаются, foreach работает с копией указанный массив, а не массив сам. foreach имеет некоторые побочные эффекты на указатель массива.


Насколько я могу судить, третий тест, на который вы ссылались, не выполняет ни одну из этих двух вещей - что означает, что оба теста не делают одно и то же - что означает, что вы не сравниваете два способа написания одного и того же кода. .

(Я бы также сказал, что такого рода микрооптимизация вообще не будет иметь значения в реальном приложении - но я думаю, вы уже это знаете, и просто спросили из любопытства)

Есть также одна вещь, которая не подходит в этом тесте: тест проводится только один раз; для «лучшего» теста, возможно, было бы полезно протестировать все эти тесты более одного раза - с временными интервалами порядка 100 микросекунд, не так уж и много, чтобы сделать огромную разницу.
(Учитывая, что первый тест варьируется от 300% до 500% при нескольких обновлениях ...)


Для тех, кто не хочет нажимать, вот первый тест (я получил 3xx%, 443% и 529%) :

foreach($aHash as $key=>$val) {
    $aHash[$key] .= "a";
}

И третий (100%) :

$key = array_keys($aHash);
$size = sizeOf($key);
for ($i=0; $i<$size; $i++) {
    $aHash[$key[$i]] .= "a";
}
2 голосов
/ 11 марта 2010

Извините, но сайт ошибся. Вот мой собственный скрипт, который показывает, что они почти одинаковы по скорости, и на самом деле foreach работает быстрее!

<?php

function start(){
    global $aHash;
    // Initial Configuration
    $i   = 0;
    $tmp = '';
    while($i < 10000) {
      $tmp .= 'a';
      ++$i;
    }
    $aHash = array_fill(100000000000000000000000, 100, $tmp);
    unset($i, $tmp);
    reset($aHash);
}

/* The Test */
$t = microtime(true);
for($x = 0;$x<500;$x++){
    start();
    $key = array_keys($aHash);
    $size = sizeOf($key);
    for ($i=0; $i<$size; $i++) $aHash[$key[$i]] .= "a";
}
print (microtime(true) - $t);

print ('<br/>');

$t = microtime(true);
for($x = 0;$x<500;$x++){
    start();
    foreach($aHash as $key=>$val) $aHash[$key] .= "a";
}
print (microtime(true) - $t);
?>

Если вы посмотрите на исходный код тестов: http://www.phpbench.com/source/test2/1/ и http://www.phpbench.com/source/test2/3/, вы увидите, что $ aHash не заполняется исходными данными после каждой итерации. Он создается один раз в начале, затем каждый тест запускается X раз. В этом смысле вы работаете с постоянно растущим $ aHash для каждой итерации ... в psuedocode:

iteration 1: $aHash[10000000000000]=='aaaaaa....10000 times...a';
iteration 2: $aHash[10000000000000]=='aaaaaa....10001 times...a';
iteration 2: $aHash[10000000000000]=='aaaaaa....10002 times...a';

Со временем данные для всех тестов увеличиваются для каждой итерации, поэтому, конечно, к итерации 100 метод array_keys работает быстрее, поскольку он всегда будет иметь одинаковые ключи , где в качестве Цикл foreach должен бороться с постоянно растущим набором данных и хранить значения в массивах!

Если вы запустите мой код, представленный выше, на своем сервере, вы ясно увидите, что foreach быстрее, аккуратнее и понятнее.

Если автор сайта хотел, чтобы его тест выполнял то, что он делает, то он, безусловно, неясен, а в противном случае это недействительный тест.

0 голосов
/ 10 марта 2010

Результаты эталонных измерений для таких микроизмерений, полученные на работающем, загруженном веб-сервере, который подвержен чрезмерным нагрузкам и другим воздействиям, следует игнорировать. Это не среда для сравнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...