Прежде всего, я понимаю, что в 90% приложений разница в производительности совершенно не важна, но мне просто нужно знать, какая конструкция является более быстрой. Это и ...
Информация, доступная в настоящее время о них в сети, сбивает с толку. Многие люди говорят, что foreach - это плохо, но технически он должен быть быстрее, поскольку предполагает упрощение написания обхода массива с использованием итераторов. Итераторы, которые, как предполагается, будут быстрее, но в PHP также явно очень медленны (или это не PHP?). Я говорю о функциях массива: next () prev () reset () и т. Д., Если это даже функции, а не одна из тех особенностей языка PHP, которые выглядят как функции.
Чтобы немного сузить круг вопросов: мне неинтересно обходить массивы с шагом, превышающим 1 (также нет отрицательных шагов, то есть обратной итерации). Меня также не интересует переход к произвольным точкам и обратно, просто от 0 до длины. Я также не вижу, чтобы манипулирование массивами с более чем 1000 ключами происходило на регулярной основе, но я действительно вижу, как массив проходит несколько раз в логике приложения! Также, что касается операций, в основном только манипуляции со строками и эхо.
Вот несколько справочных сайтов:
http://www.phpbench.com/
http://www.php.lt/benchmark/phpbench.php
Что я слышу везде:
foreach
медленный, и, следовательно,for
/while
быстрее- PHP
foreach
копирует массив, который выполняет итерацию ; чтобы сделать это быстрее вам нужно использовать ссылки - код вроде этого: быстрее, чем
$key = array_keys($aHash); $size = sizeOf($key);
for ($i=0; $i < $size; $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
быстрее чемfor
foreach
быстрее, чемfor
для хеш-таблицы
Может кто-нибудь объяснить?
- Я делаю что-то неправильно?
- Действительно ли справочная вещь PHP foreach имеет значение? В смысле, почему бы не скопировать, если пройти по ссылке?
- Какой эквивалентный код итератора для оператора foreach; Я видел несколько в сети, но каждый раз, когда я их проверяю, время идет не так; Я также протестировал несколько простых конструкций итераторов, но, похоже, никогда не получил даже достойных результатов - итераторы массивов в PHP просто ужасны?
- Есть ли более быстрые способы / методы / конструкции для итерации по массиву, отличному от FOR / FOREACH (и WHILE)?
Версия PHP 5.3.0
Изменить: Ответ. С помощью людей здесь я смог собрать ответы на все вопросы. Я резюмирую их здесь:
- "Я делаю что-то неправильно?" Похоже, что консенсус таков: да, я не могу использовать эхо в тестах. Лично я до сих пор не понимаю, как echo - это какая-то функция со случайным временем выполнения или как любая другая функция чем-то отличается - это и способность этого скрипта просто генерировать точно такие же результаты foreach лучше, чем все, что сложно чтобы объяснить, хотя просто «вы используете эхо» (хорошо, что я должен был использовать). Тем не менее, я признаю, что тест нужно проводить с чем-нибудь получше; хотя идеального компромисса в голову не приходит.
- «Действительно ли справочная функция PHP foreach имеет значение? Я имею в виду, почему она не копирует ее, если вы передаете ее по ссылке?» ircmaxell показывает, что да, дальнейшее тестирование, похоже, доказывает, что в большинстве случаев ссылка должна быть быстрее - хотя, учитывая мой приведенный выше фрагмент кода, определенно не означает все. Я согласен, что проблема, вероятно, слишком неинтуитивна, чтобы возиться с ней на таком уровне, и потребует чего-то экстремального, например декомпиляции, чтобы определить, что лучше для каждой ситуации.
- "Каков эквивалентный код итератора для оператора foreach? Я видел несколько таких в сети, но каждый раз, когда я их тестирую, время идет далеко; я также тестировал несколько простых конструкций итераторов, но, похоже, никогда не получал даже достойных результатов - итераторы массивов в PHP просто ужасны? " ircmaxell предоставил ответ ниже; хотя код может быть действителен только для версии PHP> = 5
- «Существуют ли более быстрые способы / методы / конструкции для итерации по массиву, кроме FOR / FOREACH (и WHILE)?» Спасибо Гордону за ответ. Использование новых типов данных в PHP5 должно дать либо повышение производительности, либо увеличение памяти (что может быть желательно в зависимости от вашей ситуации). Хотя с точки зрения скорости многие из новых типов массивов кажутся не лучше, чем array (), splpriorityqueue и splobjectstorage кажутся значительно быстрее. Ссылка предоставлена Гордоном: http://matthewturland.com/2010/05/20/new-spl-features-in-php-5-3/
Спасибо всем, кто пытался помочь.
Я, скорее всего, буду придерживаться foreach (не справочной версии) для любого простого обхода.
Ответы:
Мое личное мнение - использовать то, что имеет смысл в контексте. Лично я почти никогда не использую
for
для обхода массива. Я использую его для других типов итераций, ноforeach
это слишком просто ... В большинстве случаев разница во времени будет минимальной.Главное, на что стоит обратить внимание:
Это дорогой цикл, поскольку он вызывает счетчик на каждой итерации. Пока вы этого не делаете, я не думаю, что это имеет значение ...
Что касается ссылки, имеющей значение, PHP использует копирование при записи, поэтому, если вы не записываете в массив, будет относительно мало накладных расходов во время цикла. Однако, если вы начнете изменять массив внутри массива, вы начнете видеть различия между ними (поскольку нужно будет скопировать весь массив, а ссылка может просто изменить встроенную) ...
Что касается итераторов,
foreach
это эквивалентно:Что касается более быстрых способов итерации, это действительно зависит от проблемы. Но мне действительно нужно спросить, почему? Я понимаю, что хочу сделать вещи более эффективными, но я думаю, что вы тратите время на микрооптимизацию. Помните,
Premature Optimization Is The Root Of All Evil
...Изменить: на основании комментария я решил провести быстрый тест ...
И результаты:
Поэтому, если вы изменяете массив в цикле, использовать ссылки в несколько раз быстрее ...
И накладные расходы только на ссылку на самом деле меньше, чем копирование массива (это на 5.3.2) ... Таким образом, кажется (по крайней мере, на 5.3.2), как будто ссылки значительно быстрее ...
источник
"the better standard way to adopt."
- не единственный критерий выбора того, что следует принять. особенно в таком надуманном случае. Честно говоря, вы просто зря теряете времяНе уверен, что это так уж удивительно. Большинство людей, пишущих на PHP, не очень хорошо разбираются в том, что на самом деле делает PHP на «голом железе». Я скажу несколько вещей, которые будут верны в большинстве случаев:
Если вы не изменяете переменную, в PHP будет быстрее работать по значению. Это потому, что ссылки в любом случае подсчитываются, а по значению меньше работы. Он знает, что как только вы измените этот ZVAL (внутренняя структура данных PHP для большинства типов), ему придется разорвать его простым способом (скопировать и забыть о другом ZVAL). Но вы его никогда не изменяете, так что это не имеет значения. Ссылки усложняют это, поскольку требуется больше учета, чтобы знать, что делать, когда вы изменяете переменную. Так что, если вы - только для чтения, как ни парадоксально, лучше не использовать &. Я знаю, это нелогично, но это также правда.
Foreach не медленный. А для простой итерации условие, по которому выполняется проверка - «я в конце этого массива» - выполняется с использованием собственного кода, а не кодов операций PHP. Даже если это кэшированные коды операций APC, он все равно медленнее, чем набор собственных операций, выполняемых на голом железе.
Использование цикла for "for ($ i = 0; $ i <count ($ x); $ i ++) медленно из-за count () и отсутствия способности PHP (или действительно любого интерпретируемого языка) оценивать при синтаксическом анализе время, изменяет ли что-либо массив, что предотвращает однократную оценку счетчика.
Но даже если вы исправите это с помощью "$ c = count ($ x); for ($ i = 0; $ i <$ c; $ i ++)" $ i <$ c в лучшем случае представляет собой набор кодов операций Zend, как и $ i ++. В течение 100000 итераций это может иметь значение. Foreach знает на нативном уровне, что делать. Никаких кодов операций PHP не требуется для проверки условия «Я в конце этого массива».
А как насчет старой школы "while (list ("?) Ну, использование each (), current () и т. Д. Потребует хотя бы одного вызова функции, что не медленно, но не бесплатно. Да, те снова являются кодами операций PHP! Так что while + list + также имеет свои затраты.
По этим причинам foreach по понятным причинам является лучшим вариантом для простой итерации.
И не забывайте, что его легче всего читать, поэтому он беспроигрышный.
источник
Одна вещь, на которую следует обратить внимание в тестах (особенно на phpbench.com), заключается в том, что даже если цифры верны, тесты нет. Многие тесты на phpbench.com выполняют тривиальные функции и злоупотребляют способностью PHP кэшировать поиск в массиве для искажения результатов тестов или в случае итерации по массиву фактически не тестируют его в реальных случаях (никто не пишет пустое значение для петли). Я провел свои собственные тесты, которые, как я обнаружил, в значительной степени отражают результаты реального мира, и они всегда показывают, что родной синтаксис итераций языка
foreach
выходит на первое место (сюрприз, сюрприз).источник
На дворе 2020 год, и благодаря php 7.4 и opcache многое изменилось. .
Вот тест OP ^, запущенный как unix CLI , без частей echo и html.
Тест запускался локально на обычном компьютере.
Измененный скрипт теста:
Вывод:
Как видите, эволюция безумна, примерно в 560 раз быстрее. чем сообщалось в 2012 году.
На моих машинах и серверах, после моих многочисленных экспериментов, основы для циклов были самыми быстрыми. Это еще яснее при использовании вложенных циклов ( $ i $ j $ k ..)
Он также является наиболее гибким в использовании и, на мой взгляд, лучше читается.
источник
Я думаю, но не уверен:
for
цикл требует двух операций для проверки и увеличения значений.foreach
загружает данные в память, затем перебирает все значения.источник