Fi1osof 15 ноября 2014 2 1
Многие, кто сталкивался с xPDO, знают метод $modx->getCollection(). Он возвращает массив полученных xPDO-объектов. Но есть еще метод $modx->getIterator(), который выполняет примерно тоже самое, только гораздо выгодней в плане экономии ресурсов и быстродействия. Попробую кратко описать разницу. $modx->getCollection() получает и возвращает массив сразу со всеми полученными объектами. То есть у нас в момент выполнения данного метода расходуются ресурсы под наполнение переменной-массива сразу всеми полученными объектами. А $modx->getIterator() просто создает дескриптов для перечисления, не инициализируя объектов напрямую.

Рассмотрим два пример.

Пример 1.
$q = $modx->newQuery('modResource');
$q->limit(15000);
$docs = $modx->getCollection('modResource', $q);
foreach($docs as $doc){}

Время выполнения: 22 сек.
Использование памяти: 389 Mb

Пример 2.
$q = $modx->newQuery('modResource');
$q->limit(15000);
$docs = $modx->getIterator('modResource', $q);
foreach($docs as $doc){}

Время выполнения: 19 сек.
Использование памяти: 8.9 Mb

Как видите, разница во времени не особо большая, но вот в потреблении памяти просто огромная. Почему так получается? В первом случае MODX получает данные всех объектов и набивает их в результирующий массив, а далее уже происходите перечисление его элементов-объектов. А во втором случае объекты инициализируются только на каждом шаге цикла, при этом в единицу времени существует только одна переменная-объект, затираемая на следующем шаге цикла. В итоге память занимает только один объект, а не 15000.

Плюс использования $modx->getIterator() еще и в том, что можно обрубить перечисление, к примеру, еще на первом объекте (в данном случае чисто для примера, по какому-либо условию), что сильно сократит время выполнения скрипта, так как в итоге будет инициализирован только один объект, в то время, как в случае с $modx->getCollection() в любом случае будут инициализированы все 15000 объектов. В связи с этим рассмотри еще два примера.

Пример 1.
$q = $modx->newQuery('modResource');
$q->limit(15000);
$docs = $modx->getCollection('modResource', $q);
foreach($docs as $doc){
break;
}

Время выполнения: 23 сек.
Использование памяти: 389 Mb

То есть почти без изменений. Потому что перечисление массива не занимает много времени, а основное время уходит именно на создание пятнадцати тысяч объектов.

Пример 2.
$q = $modx->newQuery('modResource');
$q->limit(15000);
$docs = $modx->getIterator('modResource', $q);
foreach($docs as $doc){
break;
}

Время выполнения: 0.1343 сек.
Использование памяти: 8.25 Mb

Вот здесь время выполнения почти мгновенно. Почему? Давайте еще раз распишем логику:
1. MODX формирует и выполняет SQL-запрос (и в первом и во втором случае это одно и то же время).
2. $modx->getIterator() создает дескриптор цикла (но не создает самих xPDO-объектов).
3. Выполняет первый цикл, инициализирует один xPDO-объект и прекращает выполнение цикла операндом break;
За счет этого и обеспечивается скорость, так как в первом случае даже если нам надо выполнить всего один шаг цикла, у нас все равно MODX инициирует 15000 объектов.

В общем, берите на вооружение :)

P.S. В новой версии пакета modxSite в getdata-процессоры я наконец-то введу этот метод, что сделает их еще более быстрыми и менее ресурсоемкими.

P.P.S. Кстати, если первый пример заменить на такой:
$q = $modx->newQuery('modResource');
$q->limit(15000);
foreach($modx->getCollection('modResource', $q) as $doc){
break;
}
то есть не создавать переменную $docs, а сразу в цикл закинуть результат выполнения метода $modx->getCollection(), то получаем более привлекательные цифры:
Время выполнения: 22.5 сек.
Использование памяти: 26.25 Mb
1 комментарий
Tramp13571
Tramp1357 16 ноября 2014г в 01:53 #
то есть при использовании итератора на каждом шаге выполнается по запросу? Или при вызове getIterator сразу кладется в буфер вся выборка, а потом из нее формируются объекты?
Fi1osof1
Fi1osof 16 ноября 2014г в 02:10 #
Нет, не выполняется по запросу. Это равносильно while($row = $s->fetch(xPDO::FETCH_ASSOC)){}. Смотри код.
Tramp13571
Tramp1357 16 ноября 2014г в 18:10 #
Понял
V
Valentin Kuzmenko 19 ноября 2014г в 15:21 #
хорошая заметка))))
Авторизуйтесь или зарегистрируйтесь (можно через соцсети ), чтобы оставлять комментарии.