pdoParser против modParser

Третьего дня Сергей Шлоков провёл новый тест скорости работы парсера MODX и шаблонизаторов Fenom и Smarty.

До Smarty мне дела нет, но с итоговыми выводами, что никакой разницы в скорости между синтаксисом MODX и Fenom не видно, я категорически не согласен.



Итак, что нужно прояснить. У оригинального парсера MODX modParser есть две, на мой взгляд, фундаментальные проблемы:

Во-первых, каждый тег при разборе превращается в PHP объект modTag и в нём запускается метод process. То есть, если в чанке указан просто [[+id]], то MODX вместо обычной замены его через str_replace будет создавать новый объект и парсить.

Во-вторых, из-за своей рекурсивной природы, MODX выполняет все условия в чанках. Он просто не знает, во что могут превратиться эти условия на пятой, например, итерации. Причём делает он это изнутри наружу.
То есть, если вы прячете какой-то кусок оформления для вывода только нужным пользователям за условиями в чанке — именно этот кусок и будет первым делом разобран, а потом MODX решит, нужно ли его выводить, когда проверит условие с юзером. Народ придумывает разные костыли для обхода этого момента, чтобы парсить только нужное, типа [[![[+user:is=`admin`:then=`auth`:else=`guest`]]]].

Так вот, когда вы только установили pdoTools на сайт, он по умолчанию подсовывает системе свой pdoParser, который умеет заменять простые теги типа [[*id]], [[+id]], [[++setting]], [[%lexicon]] через str_replace, без создания modTag.

Просто после установки pdoTools эти теги на страницах сайта будут разбираться быстрее и с меньшими затратами памяти. Но с чанками, которые вызываются через сниппеты, используя $modx->getChunk() разницы особой не будет.

Для того, чтобы добиться такого же эфекта при выводе чанков сниппетам, в них нужно использовать
$pdo = $modx->getService('pdoTools');
$pdo->getChunk(...);
С рекурсивной природой парсера MODX можно справиться только использованием нормального шаблонизатора, например Fenom. Тогда все условия буду разбираться cнаружи внутрь, как в обычном PHP скрипте, а не наоборот, как у modParser.

Зная всё это, я создал 2 сайта на modhost.pro: первый сайт без pdoTools, а второй с ним, все настройки по умолчанию.

Дальше написал сниппет Test:
<?php
// $pdo = $modx->getService('pdoTools'); // раскомментируем позже, на втором сайте

$items = [];
// Здесь мы будем менять количество проходов
for ($i = 1; $i < 100; $i++) {
  $data = ['id' => rand(), 'pagetitle' => 'page' . rand()];
  // А здесь переключать на $pdo->getChunk
  $items[] = $modx->getChunk('test', $data);
}

$output = number_format(microtime(true) - $modx->startTime, 4) . "\n";
$output .= number_format(memory_get_usage() / 1048576, 4) . "mb\n";
$output .= implode("\n", $items);

return $output;

Затем простейший тестовый чанк с тегами MODX
<p>[[+id]] - [[+pagetitle]] [[+id:is=`10`:then=`1`:else=``]]</p>

И он же, но на Fenom
<p>{$id} - {$pagetitle} {$id == 10 ? 1 : ''}</p>
Сниппет вызываем на главной странице сайта, как Сергей и предлагает.

Результаты


Сайт без pdoTools, чанк с тегами MODX, работает modParser.
Просто голый MODX по умолчанию:

— 100 проходов: 0.0382s, 4.2729mb
— 1000 проходов: 0.1785s, 4.3551mb
— 10000 проходов: 1.6821s, 5.3727mb

Второй сайт, с установленным pdoTools.
Теги MODX, в сниппете используется $modx->getChunk:

— 100 проходов: 0.0167s, 1.1837mb
— 1000 проходов: 0.1248s, 1.2658mb
— 10000 проходов: 1.1974s, 2.2834mb

Уже быстрее, видимо из-за каких-то моих оптизаций в pdoParser, но явно не из-за быстрой обработки плейсхолдеров.

Меняем сниппет и включаем работу через $pdo->getChunk(). Чанк всё еще с тегами MODX:
— 100 проходов: 0.0085s, 1.1979mb
— 1000 проходов: 0.0495s, 1.2802mb
— 10000 проходов: 0.3767s, 2.2978mb

А вот теперь мы видим эту самую простую замену плейсхолдеров на значения без создания modTag.

Ну и вишенка на торте — меняем синтаксис чанка на Fenom:
— 100 проходов: 0.0096s, 1.9815mb
— 1000 проходов: 0.0110s, 2.0637mb
— 10000 проходов: 0.0268s, 3.0814mb

Как видно, на небольшом количестве Fenom даже чуть медленее, из-за компиляции чанков, но и чанк очень простой. А дальше он уверенно вырывается вперёд.

Если у вас будет меньше проходов, но больше условий и тяжелее чанки — результаты будут примерно такие же. Как правило, в MODX чанки всё-таки посложнее, чем 2 тега и 1 условие.

Заключение


Давайте еще раз, итоговые цифры для наглядности:

В самом лёгком варианте на 100 проходов чистый modParser выдёт 0.0382s против 0.0096s у pdoParser с Fenom. Разница в 4 раза.

В самом тяжёлом варианте на 10000 проходов соответственно 1.6821s против 0.0268s. Это уже разница в 62 раза!

Как @Сергей Шлоков умудрился провести свои тесты и не найти никакой разницы — я не понимаю. У меня она есть и очень наглядная.
Василий Наумкин
26 апреля 2022, 08:11
modx.pro
804
+27

Комментарии: 8

Иван
26 апреля 2022, 22:23
0
То есть, если вы прячете какой-то кусок оформления для вывода только нужным пользователям за условиями в чанке — именно этот кусок и будет первым делом разобран, а потом MODX решит, нужно ли его выводить, когда проверит условие с юзером.
Прошу прощения за мой дилетантский вопрос, но не лучше ли было исправить этот косяк и прислать код разработчикам MODX на Гитхаб? Обработку простых тегов тоже можно было бы предложить оптимизировать в коде основного парсера.
    Василий Наумкин
    27 апреля 2022, 07:45
    +2
    Как ты исправишь основную фишку рекурсивого парсера — рекурсивный разбор тегов? Это просто такой метод работы, который очень многим в MODX и нравится. Напихать тегов друг на друга, парсер сам разберётся.

    Ну а замена простых плейхолдеров… Самый главный архитектор системы об этом давно знает и ничего менять не хочет.

    Хочешь исправить — ставь pdoTools и пользуйся, для того расширения и нужны.
      Иван
      27 апреля 2022, 11:47
      0
      Как ты исправишь основную фишку рекурсивого парсера — рекурсивный разбор тегов?
      Если я правильно понял, то проблема в том, что парсер MODX парсит изнутри, а не снаружи, поэтому парсит лишнее. Не понял почему это нельзя исправить.
        Василий Наумкин
        27 апреля 2022, 11:55
        0
        Не понял почему это нельзя исправить.
        Потому, что тогда парсер перестанет быть рекурсивным и ты не сможешь делать вот так:
        [[~[[+id]]]]

        Смысл в том, что после разбора внутреннего тега [[+id]] получается новый тег, например [[~9]], а он уже превращается в ссылку на документ с id = 9.

        То есть, нужно парсить этот тег минимум 2 раза — это и есть рекурсия. Так весь MODX и работает, это его чуть ли не основная фишка.
          Иван
          27 апреля 2022, 16:51
          0
          То есть, нужно парсить этот тег минимум 2 раза — это и есть рекурсия. Так весь MODX и работает, это его чуть ли не основная фишка.
          Я не вижу проблемы где-то эту рекурсию использовать так, а где-то иначе. Например, для условий «if-else» сделать другую логику. Логично сначала парсить условие, а потом уже контент. А про «фишку» впервые слышу.
            Василий Наумкин
            27 апреля 2022, 16:57
            +1
            Ну раз ты не видишь проблемы — исправляй и шли коммит в репозиторий MODX.
              Руслан Алеев
              27 апреля 2022, 20:21
              +1
              На самом деле, если есть что предложить, то отправьте issue/PR, возможно, действительно ускорите MODX. Тем более MODX 3 пока еще в полу-рабочем режиме :)
      Роман
      27 апреля 2022, 15:09
      +1
      Василий спасибо за разбор и за pdoTools. Давно заметил, что modParser больше памяти потребляет, да и по скорости иногда проигрывает. pdoTools отличный инструмент, редко встречаю сайты, которые бы его не использовали.
        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
        8