В рамках приведения мыслей в порядок составила следующую блок-схему запекания шаблонов (напоминаю, что шаблон - это предварительная версия фрагмента страницы, типа "{{nickname}}, {{species}} ур. {{level}}", которая превращается в "Вася, бульбазавр ур. 50"): блок-схема.
Трудность в ней представляет только один момент: раскрытие запекаемого шаблона должно быть не сильно сложнее, чем раскрытие шаблона, который запекать не предполагается, иначе выигрыша от такой оптимизации не будет. Это преграда, которую я всё не могу преодолеть...
Представим, что кнопка "Случ. тренер" выбирает между 3000 тренерами (хотя вообще она выбирает только среди активных). Когда профиль каждого из этих тренеров показывается в первый раз, движок "запекает" его, чтобы следующий гость в течение жизни кэша (скажем, сутки) увидел уже заготовленные данные, и процесс потратит меньше ресурсов. На запекание уходят дополнительные ресурсы. Если 10 игроков посмотрят по 100 разных случтренеров, движок скорее проиграет в затратах... Также он ничего не выиграет, если данные из кэша (запечённые профили тренеров) будут постоянно сбрасываться (это тоже требует ресурсов), а не храниться сутки - поэтому туда не запекается экспа.
Однако существенный выигрыш должен быть по профилям тренеров, которых смотрят часто - скажем, активным игрокам - если он не будет сбрасываться от повсегдневного игрового процесса. И он должен перевесить лишние затраты на запекание. Такая вот математика...
В прошлый раз я рассказала про запекание шаблонов, которое позволяет снизить нагрузку за счёт запоминания постоянных частей страниц и заполнения только динамических.
Сказать по правде, оно довольно тяжело даётся... Понадобилось довольно много времени "за чертежами" (над блокнотом), чтобы выяснить, что в конструкции {{player.user.login}} постоянство нужно проверять не у игрока, пользователя и его логина, а у переходов "шаблон -> player", "player -> user" и запроса "user->template(login)". В конечном счёте постоянство будет опрошено у тех же объектов, но разница в логике довольно велика.
В связи с этим подошло время переписывать парсер шаблонов, чем я сейчас и занимаюсь. Парсер превращает строчку "{{player.user.login}}" в команду языка программирования "$this->keyword(['player', 'user', 'login'])". Это, опять же, должно выполняться только раз, когда шаблон сохраняется (предкомпиляция), иначе подобное превращение пришлось бы делать прямо во время генерации страницы, каждый раз заново. Сейчас предкомпилятор - довольно примитивный служебный сценарий, который хотя справляется со своей работой (его содержимое не менялось уже больше года), но не очень удобен для расширения кода. В общем, моя задача сейчас - разнести этот структурный код на классы и объекты. К счастью, это задача гораздо проще, чем с наскоку сделать запекание шаблонов, и после её решения с выпечкой тоже будет проще.
Ещё я сегодня узнала из передачи "16 бит тому назад", что главным вкладом Джона Кармака в жанр 3Д-экшенов заключался не в изобретении методов генерации 3Д-графики, а именно в оптимизации вполне уже известных методов, чтобы игра могла идти на нормальных домашних компах со скоростью, позволяющей динамичную боёвку. Так что я заново воодушевилась, уверившись в важности оптимизации.
Обновлён открытый репозиторий, содержащий все файлы движка кроме собственно игры. Можно увидеть, что изменений была масса: теперь используются пространства имён (я так надеялась, что их доработают в ближайших версиях PHP, но приходится работать с тем, что есть), выделены в отдельный класс типы данных ValueType, добавлены регистры данных RegisterSet, приостанавливаемые методы Coroutine, много функционала пересажено на интерфейсы вместо классов (в частности, на Promise)... Долго рассказывать.
Что делается сейчас. Сегодня мне нужно решить проблему запекания шаблонов.
Шаблон - это текстовая заготовка, которая превращается затем для пользователя в кусок веб-страницы. Например: "Покемон {{имя}}, вид {{вид}}, тренер {{тренер.имя}}, ур. {{уровень}}". При подстановке конкретного покемона в этот шаблон мы получаем "Покемон Вася, вид бульбазавр, тренер EvilCat, ур.10". Шаблоны могут быть довольно большими и включать сценарии ("если покемон в яйце, показать одно... если вылупившийся, другое...") и подшаблоны.
Если на странице показывается 20 покемонов - это двадцать шаблонов с информацией о них. В которых могут быть подшаблоны. И у самой страницы - тоже. В общем, это гибкая система, но также и нагрузная. Поэтому хорошая практика - хранить результат раскрытия затратных шаблонов в кэше, то есть на диске или в памяти. Тогда вместо заполнения каждого отдельного поля {{имя}}, {{вид}}... Нужно просто достать готовый текст о бульбазавре Васе.
Не всё так просто, конечно. Что если тренер переименует покемона, а игра продолжит показывать готовый текст, где он всё ещё Вася? Что если админы переименуют вид покемона? Игра должна знать, когда "сбрасывать кэш" - забывать готовые тексты и делать их заново. Отчасти она делает это по времени, очищая кэш где-то раз в сутки. Но на некоторые изменения реакция должна быть мгновенной. Также не имеет смысл включать в готовый текст значение опыта {{xp}}, поскольку он будет меняться сиюминутно и сбрасывать в остальном годный кэш. Это значение должно остаться незаполненным полем. Также нет смысла хранить готовые тексты для шаблонов, где не так уж много полей... В общем, все эти нюансы необходимо учесть в коде, чтобы сайт работал быстро даже под большой нагрузкой.
Не секрет, что давно ожидаемые обновления на сайте задерживаются... >_< Раньше они задерживались отчасти из-за нехватки времени - офисная работа поглощала всё время которое было; отчасти из-за желания сделать подольше, но получше. Теперь время образовалось и в большом количестве, и я могу делать за неделю то, на что раньше нужно было потратить полтора месяца выходных! Ура %)
Тем не менее, желание сделать получше осталось. С версии движка, залитой на GitHub, утекло много времени и прибыло хороших, правильных изменений. Во многих местах строчки кода удалось сократить на треть благодаря применению генераторов как приостанавливаемых методов. Всюду царит асинхронность и обещания (и я вовсе не об обещании вылить обновления к какому-то сроку %).
Так получилось, что одновременно с этим у двух активистов нашего сайта сейчас нет возможности над ним работать. Да и учебный год начался у всех, так что пока я строчу, активности на сайте не прибавляется. Возможно, чтобы разрядить обстановку, мне не помешает вести дневник разработчика? Будет ли интересно читать о технической работе и следить за выливками в репозиторий? Я-то люблю обсуждать такие вещи, но пока дело дойдёт до видимых последствий, которые может обсудить каждый, я могу на много записей распинаться сама с собой... %)