Подтвердить что ты не робот

Производительность цикла для PHP в PHP

Как мое исследование заставляет меня думать, что циклы for - это самая быстрая итерационная конструкция в PHP... чтобы сделать ее более ясной, какая из следующих, по вашему мнению, будет быстрее?

Пример ONE

for ($i = 0; $i < count($myLargeArray); $i++ ) {
    echo myLargeArray[$i];
}

Пример TWO​​h3 >

$count = count($myLargeArray);
for ($i = 0; $i < $count; $i++ ) {
    echo myLargeArray[$i];
}

Моя логика следует, что на каждой итерации в примере один доступ к длине myLargeArray на каждой итерации является более вычислительно дорогостоящим, чем доступ к простому целочисленному значению, как в примере 2. Это правильно?

4b9b3361

Ответ 1

Первый способ медленнее, потому что функция count() должна вызываться на каждой итерации цикла. Сам метод count() довольно быстрый, но все еще есть некоторые накладные расходы при вызове функции вообще. Перемещая его за пределы цикла, вы выполняете так называемое " движение инвариантного цикла цикла", или иногда "подъем".

Здесь есть целый семейство оптимизаций, которые интересны для изучения.

Сказав все это, редко приходится об этом особо подчеркивать. В вашем примере здесь ввод-вывод повторения вывода, вероятно, в 10 раз больше, чем вы сохраняете в своей "оптимизации". И если вы делаете что-нибудь еще внутри своей петли, ваша оптимизация означает все меньше и меньше.

Я ненавижу быть мокрым одеялом, но для более чем 90% вашего кода производительность не является проблемой. Особенно, когда вы говорите о веб-приложениях, которые начинаются с ввода-вывода более чем на 90%.

Тем не менее, когда вы думаете, что ваш код виноват, вы должны:

  • Определите пример использования, который вам нужно оптимизировать.
  • Измерьте производительность вашего кода.
  • Найдите узкие места
  • Определите области, которые вы можете улучшить, и решите, стоит ли вам их улучшить.
  • Внесите изменения в свой код.
  • Вернитесь к шагу 2

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

Ответ 2

Пример 2. Не считайте элементы каждой итерацией.

Обновлено: мне только что сказали, что значение предварительно вычисляется: nNumOfElements specifies how many values are currently stored in the array. This is also the number that счетчик ($ массив) returns.

Мне кажется, что функция count() буквально ничего не делает, кроме того, что тратит несколько микросекунд и тактовых циклов (для тех, кто знает ассемблер).

Читайте здесь: Понимание реализации внутреннего массива PHP (исходный код PHP для разработчиков PHP - часть 4).

Возможно, вы можете попробовать foreach range:

foreach (range(0, (count(array)) as $number) {
    echo $number;
}

Ответ 3

Самая быстрая конструкция в этом случае является фактически циклом foreach:

foreach($myLargeArray as $element) {
    echo $element;
} 

Foreach() также хорош тем, что он всегда заканчивается, тогда как опечатка может оставить вас с бесконечным циклом, когда вы используете для().

Ответ 4

Ясно, что пример один медленнее. Условие $i < count($myLargeArray) оценивается на каждой итерации, таким образом, подсчитывая массив несколько раз.

Проверьте этот и другие критерии на http://www.phpbench.com/

Изменить: они посмотрели на исходный код, и он был предварительно вычислен.

Однако время обработки тратится на эти многочисленные вызовы функций. Вот почему производительность падает. Массив "подсчитывается" несколько раз.

Ответ 5

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

Ответ 6

Поэтому я решил на самом деле количественно определить несколько вещей, в интересах получения некоторых реальных чисел. Вот базовый код, цикл, который строит большой массив из 100000 целых чисел.

$x = array();
for ($idx=0; $idx<100000; $idx++)
    $x[] = $idx;

Среднее время выполнения: 85 ms. Это включает время запуска PHP, анализ программы, запуск и выход. Теперь я добавляю еще один цикл, который выполняет итерацию через массив:

for ($idx=0; $idx<count($x); $idx++) { 
    ;
}

Среднее время выполнения: 105 ms. Когда вы вычитаете время установки 85 ms, вы можете видеть, что для итерации через массив из 100 000 элементов требуется только 20 ms.

Теперь мы добавляем движение цикла с инвариантным циклом:

$m = count($x);
for($idx=0; $idx<$m; $idx++) { 
    ;
}

Среднее время выполнения: 90 ms.

С одной стороны, эта экономия огромная. Это 5 и nbsp; мс время итерации цикла вместо 20 мкс. Поэтому вы можете утверждать, что сэкономить 75%!

С другой стороны, это 15 ms. Менее времени, чем большинство людей заметят на абсурдно большом массиве.

Но это массив, который делает ничего. Посмотрим, что произойдет, когда мы выведем некоторые данные:

$m = count($x);
for ($idx=0; $idx<$m; $idx++) { 
    echo $idx;
}

Теперь время выполнения составляет 200 ms. О, смотри, я только распечатывал индекс цикла. Я даже не выводил содержимое массива.

Это просто глупо. Позвольте снова изменить программу, чтобы отобразить содержимое массива, а не только счетчик обращений:

$m = count($x);
for ($idx=0; $idx<$m; $idx++)
    echo $x[$idx];

Новое время выполнения - 212 ms. Таким образом, потребовалось 5% дольше для доступа и эха содержимого массива, чем просто эхо счетчик циклов.

Позвольте взять кого-то более раннее предложение и развернуть цикл. Я использовал это с большим успехом в C/С++ в прошлом:

$m = count($x);
for ($idx=0; $idx<$m; $idx+=5) {
    echo $x[$idx];
    echo $x[$idx+1];
    echo $x[$idx+2];
    echo $x[$idx+3];
    echo $x[$idx+4];
}

Теперь мы говорим! Мы до 206 мск. О, подожди, это примерно 3% -ное улучшение для какого-то неудобного кода. И результат выглядит ужасно. Это просто строка чисел без пробелов или чего-то еще.

Позвольте избавиться от разворачивания цикла и сделать вывод немного приятнее:

$m = count($x);
for ($idx=0; $idx<$m; $idx++)
    echo "{$x[$idx]}\n";

Время выполнения составляет 400 мкс. Да. Это много дополнительного времени (относительно говоря), чтобы получить некоторое форматирование. Может быть, использование замены строк стоит нам что-то. Вместо этого попробуйте выполнить конкатенацию строк:

$m = count($x);
for ($idx=0; $idx<$m; $idx++)
    echo $x[$idx] . "\n";

Новое время - 390 ms. Немного лучше. Попробуем разделить числа пробелом вместо новой строки:

$m = count($x);
for ($idx=0; $idx<$m; $idx++)
    echo $x[$idx] . " ";

О, вау, мы возвращаемся к 224 мск. Право на! Но что случилось? Ну, я запускаю все это на моем терминале Unix, и просто медленнее выводить числа на отдельных строках, чем выводить их на одной линии, которая обертывается.

Другими словами, скорость программы терминала прокрутки имеет больший эффект, чем что-либо еще, что мы сделали.