О стоимости доступа к объектам в PHP
Удивительное — рядом: недавно искали с нашими админами место в коде где больше всего тормозит вывод одной страницы одного из сайтов, сделанных в недрах нашей компании в незапамятные времена.
Код был довольно запутанный, попросили меня помочь. Место я вычислил. Если его закоментировать, страница начинала выдаваться не за десятки секунд, а за единицы.
Никогда такого не видел. Как вы думаете, что тормозило? Запросы к базе? Какая-то суперматематика? Сортировка, может быть? Цикл в цикле в цикле, а там внутри что-то сложное?
Вовсе нет.
После выборки из базы, данные выкладывались в массив сложных объектов, в данном месте это было массив из почти что 500 объектов, внутри объектов лежали другие объекты, а них — ещё. Заполнение этой структуры занимало немало времени, но тормозило другое — цикл перебора массива объектов с выводом свойств объектов третьей вложенности.
В цикле не было вызвано ни одной функции (кроме htmlspecialchars), а вывод всего этого хозяйства занимал порядка десятков секунд.
А какая версия PHP? В 5.4 кажется как раз были изменения на этот счет.
Комментарий для nixx:
5.3, кажется.
Комментарий для Евгения Степанищева:
Я так подозреваю, что это могло тормозить из-за ленивого чтения, нет?
Комментарий для Горбунов Олег:
Что такое «ленивое чтение»?
Комментарий для Евгения Степанищева:
Я думаю, что под ленивым чтеним имелось в виду, что выбираются объекты, которые для доставания данных по -> делают селект в БД. А при этом объект как бы есть, но не дозаполнен.
А не пробовали на синтетических тестах такое повторить? Просто 500 объектов в массив и пробежаться? Что-то как-то не верится :)
Комментарий для fantaseour.livejournal.com:
Геттеры имеются ввиду что ли? Нет, их там нет. Синтетические тесты не пробовал. А там не просто 500 объектов, там внутри объектов ещё объекты. Т. е. выглядит как-то так:
echo $A[0]->B->C;
Комментарий для Евгения Степанищева:
Хм.. заинтересовался, так как не встречал подобной проблемы, вроде даже похожие случаи часто встречались.
Сейчас попробовал простенький пример написать, но он отрабатывает мгновенно.
Может из-за того что у вас объекты более сложные? Но все равно не очень понятно почему такое может быть.
Комментарий для http://jeka.ru:
Да, неясно до конца. Возможно влияет ещё какой-то фактор (внутренние баги интепретатора, например), а может и правда, дело в объёме хранимых данных (результирующий HTML получился >500КБ, а это ещё далеко не все хранящиеся в объектах данные использовались).
Нечто подобное есть и в перле и в пайтоне.
Насколько я понимаю, поля объекта лежат в хэше, откуда
извлекаются по имени, что небесплатно. Если же неповезло и вдруг
есть много полей с совпадающим хэшем, то время будет не log(n),
а побольше.
Комментарий для masterspammer.livejournal.com:
Если будет много полей с совпадающим хешем, то тормозить будет не на извлечении, а на вставке, так как придётся пересчитать хеши.
Комментарий для Евгения Степанищева:
Зависит от реализации хэштаблицы. Вот для примера если взять явовскую реализацию (просто я её лучше всего помню), то пересчёт делается при удвоении размера (когда от хэша начинает использоваться на один бит больше), соответственно если на основе такой таблицы делать объект (что вполне может быть если используем явовскую реализацию скриптового языка), то удваиваться она будет разве что при инициализации объекта — при типовом использовании объекта число его полей обычно сильно не меняется.
В той же реализации для хэш берётся для быстрого нахождения номера списка, а в этом списке идёт уже поиск перебором. В таком случае при большом количестве совпадающих хэшей (не вызваном большим количеством ключей) пересчёта точно не будет. Пересчёт будет при увеличении числа ключей (что коррелирует с количеством совпадений) независимо от самого числа совпадений.
Комментарий для Евгения Степанищева:
А можно пример тормозящего кода? И какое количество объектов и свойств на каждом уровне цепочки «$A[0]->B -> C»?
Комментарий для kuku:
Простите, но совсем не хочется сейчас вспоминать в каком это проекте, искать этот кусок кода и ревизию в «гите», где он сохранился, чистить его и выкладывать. Слишком много усилий.