Производительность FOR против FOREACH в PHP

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

Информация, доступная в настоящее время о них в сети, сбивает с толку. Многие люди говорят, что foreach - это плохо, но технически это должно быть быстрее, поскольку предполагается упростить написание массива с помощью итераторов. Итераторы, которые опять-таки должны быть более быстрыми, но в PHP, по-видимому, тоже очень медленные (или это не PHP)? Я говорю о функциях массива: next () prev () reset () и т. Д. Хорошо, если они являются даже функциями, а не одной из тех функций языка PHP, которые выглядят как функции.

Чтобы немного сузить это : Меня не интересует обход массивов с шагами, превышающими 1 (отрицательных шагов тоже нет, т. Е. Обратная итерация). Я также не заинтересован в обходе и от произвольных точек, просто 0 к длине. Я также не вижу, чтобы манипулирование массивами с более чем 1000 клавиш происходит регулярно, но я вижу, что массив перебирается несколько раз в логике приложения! Также что касается операций, в основном только строковых манипуляций и эхо.

Вот несколько справочных сайтов:
http://www.phpbench.com/
http://www.php.lt/benchmark /phpbench.php

What я слышу везде:

  • foreach работает медленно, и, таким образом, для / , в то время как быстрее
  • PHPs 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 быстрее, чем для для хеш-таблицы

Кто-нибудь может объяснить?

  1. Я что-то не так делаю?
  2. Действительно ли справка PHP foreach что-то меняет? Я имею в виду, почему бы не скопировать его, если вы передадите по ссылке?
  3. Какой эквивалентный код итератора для оператора foreach; Я видел несколько в сети, но каждый раз, когда я проверяю их, время отстает; Я также протестировал несколько простых конструкций итераторов, но, похоже, никогда не получал даже приличных результатов - действительно ли итераторы массивов в PHP просто ужасны?
  4. Существуют ли более быстрые способы / методы / конструкции для итерации, хотя массив отличается от FOR / FOREACH? (и WHILE)?

PHP версии 5.3.0

  • foreach быстрее, чем foreach со ссылкой
  • foreach быстрее, чем для
  • foreach быстрее, чем для для хеш-таблицы

Кто-нибудь может объяснить?

  1. Я что-то не так делаю?
  2. Действительно ли справка PHP foreach действительно имеет значение? Я имею в виду, почему бы не скопировать его, если вы передадите по ссылке?
  3. Какой эквивалентный код итератора для оператора foreach; Я видел несколько в сети, но каждый раз, когда я проверяю их, время отстает; Я также протестировал несколько простых конструкций итераторов, но, похоже, никогда не получал даже приличных результатов - действительно ли итераторы массивов в PHP просто ужасны?
  4. Существуют ли более быстрые способы / методы / конструкции для итерации, хотя массив отличается от FOR / FOREACH? (и WHILE)?

PHP версии 5.3.0

  • foreach быстрее, чем foreach со ссылкой
  • foreach быстрее, чем для
  • foreach быстрее, чем для для хеш-таблицы

Кто-нибудь может объяснить?

  1. Я что-то не так делаю?
  2. Действительно ли справка PHP foreach действительно имеет значение? Я имею в виду, почему бы не скопировать его, если вы передадите по ссылке?
  3. Какой эквивалентный код итератора для оператора foreach; Я видел несколько в сети, но каждый раз, когда я проверяю их, время отстает; Я также протестировал несколько простых конструкций итераторов, но, похоже, никогда не получал даже приличных результатов - действительно ли итераторы массивов в PHP просто ужасны?
  4. Существуют ли более быстрые способы / методы / конструкции для итерации, хотя массив отличается от FOR / FOREACH? (и WHILE)?

PHP версии 5.3.0


Редактировать: Ответить

С помощью людей здесь я смог собрать воедино ответы на все вопросы. Я суммирую их здесь:

  1. «Я что-то не так делаю?» Похоже, консенсус таков: да, я не могу использовать эхо в тестах. Лично я до сих пор не понимаю, как эхо - это какая-то функция со случайным временем выполнения или как любая другая функция как-то отличается - это и способность этого скрипта просто генерировать точно такие же результаты foreach лучше, чем все, трудно чтобы объяснить, хотя просто «вы используете эхо» (хорошо, что я должен был использовать). Тем не менее, я признаю, что тест должен быть сделан с чем-то лучшим; хотя идеальный компромисс не приходит на ум.
  2. «Действительно ли PHP foreach эталонная вещь действительно меняет дело? Я имею в виду, почему бы ее не скопировать, если вы передадите по ссылке?» ircmaxell показывает, что да, это так, дальнейшее тестирование, кажется, доказывает, что в большинстве случаев ссылки должны быть быстрее - хотя, учитывая мой фрагмент кода выше, определенно не все. Я допускаю, что проблема, вероятно, слишком неинтуитивна, чтобы с ней возиться на таком уровне, и потребовалось бы что-то экстремальное, такое как декомпиляция, чтобы фактически определить, что лучше для каждой ситуации.
  3. «Что такое эквивалентный код итератора для оператора foreach; Я видел несколько в сети, но каждый раз, когда я тестирую их, время отстает; я также тестировал несколько простых конструкций итераторов, но, кажется, никогда не получаю даже приличных результатов - итераторы массивов в PHP просто ужасны? " ircmaxell предоставил ответ ниже; хотя код может быть действительным только для версии PHP> = 5
  4. " true.object_id // 2 nil.object_id // 4 100 ....

    Я играю с Ruby .object_id и заметил, что в нескольких последовательных сеансах irb я получаю эти идентичные результаты:

    false.object_id // 0
    true.object_id // 2
    nil.object_id // 4
    100.object_id // 201
    

    На самом деле каждый целое число object_id кажется быть ((значение * 2) + 1).

    С другой стороны, object_id данной строки никогда не будет прежним после выхода и повторного запуска irb.

    Это вызывает у меня несколько вопросов:

    1. существует известная схема, по которой определяются определенные object_id ? Являются ли другие в основном случайными?
    2. Идентификаторы true, false и nil не являются последовательными. Есть ли способ спросить, какой объект представлен данным идентификатором? (Мне любопытно, к чему привязаны другие однозначные и идентификаторы.)
    3. Не могли бы вы (не то, что вы должны) написать запутанный Ruby, где вы используете идентификаторы известных объектов, чтобы ссылаться на объекты, не называя их, например " ?

    Обновление

    Используя предложение Эндрю Гримма, я попытался обнаружить другие объекты с «низким идентификатором», но обнаружил, что:

    • Похоже, что в этой последовательности больше нет объектов с четным номером - идентификаторы 6, 8, 10 и т. Д. Ни на что не указывают.
    • Как видно из моего более раннего эксперимента, все нечетные идентификаторы принадлежат числам. В частности, id 1 указывает на число 0, 3 указывает на 1, 5 указывает на 2 и т. Д.

43
задан jww 22 September 2014 в 20:14
поделиться

2 ответа

В MRI object_id объекта совпадает с VALUE, который представляет объект на уровне C. Для большинства видов объектов этот VALUE является указателем на место в памяти, где хранятся фактические данные объекта. Очевидно, что при многократных запусках это место будет разным, поскольку оно зависит только от того, где система решила выделить память, а не от какого-либо свойства самого объекта.

Однако по причинам производительности true, false, nil и Fixnumобрабатываются специально. Для этих объектов в памяти не существует структуры с данными объекта. Все данные объекта закодированы в самом VALUE. Как вы уже поняли, значения для false, true, nil и любого Fixnum i, являются 0, 2, 4 и i*2+1 соответственно.

Причина, по которой это работает, заключается в том, что на любых системах, на которых работает MRI, 0, 2, 4 и i*2+1 никогда не являются действительными адресами для объекта на куче, поэтому нет никакого пересечения с указателями на данные объекта.

63
ответ дан 26 November 2019 в 22:45
поделиться

Назначение целого числа (значение * 2) + 1 и нецелых чисел (x * 2) аналогично парадоксу Гильберта Гранд-отель , в котором описывается, как разместить бесконечно больше гостей в бесконечном отеле.

Что касается поиска объектов по их идентификатору, существует ObjectSpace._id2ref (object_id) . Если в вашей реализации нет ObjectSpace.

31
ответ дан 26 November 2019 в 22:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: