Twig: рендеринг против включения

Создаю интернет-магазин. У меня проблемы с производительностью, если я использую функцию ветки «render» вместо «include».

Вот код, который отображает каталог продукции:

контроллер каталога:

<?php
// src/Acme/StoreBundle/Controller/Product/Catalog.php

namespace Acme\StoreBundle\Controller\Product;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class CatalogController extends Controller
{
    /**
     * @Template()
     */
    public function productAction(\Acme\StoreBundle\Entity\Product\Category $category)
    {
        $qb = $this->getDoctrine()
            ->getRepository('StoreBundle:Product')
            ->createQueryBuilder('product')
            ->select('partial product.{id, token, name}')
            ->innerJoin('product.categoryRelation', 'categoryRelation')
            ->where('categoryRelation.category = :category_id');

        $qb->setParameters(array(
            'category_id'  => $category->getId(),
        ));

        $products = $qb->getQuery()
            ->getResult();

        return $this->render('StoreBundle:Product\Catalog:product.html.twig', array(
            'category' => $category,
            'products' => $products,
        ));
    }
}

... шаблон для контроллера каталога:

{# src/Acme/StoreBundle/Resources/views/Product/Catalog/product.html.twig #}
{% extends 'AcmeDemoBundle::layout.html.twig' %}

{% block content %}
    <h1>{{ category.name }}</h1>

    <ul>
    {% for product in products %}
        <li>
            {#% render "StoreBundle:Product:show" with { product: product } %#}
            {% include "StoreBundle:Product:show.html.twig" with { product: product } %}
        </li>
    {% endfor %}
    </ul>

{% endblock %}

... контролер продукта:

<?php
// src/Acme/StoreBundle/Controller/Product.php

namespace Acme\Enter\StoreBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

use Enter\StoreBundle\Entity\Product;

class ProductController extends Controller
{
    /**
     * @Template()
     */
    public function showAction(Product $product)
    {
        return array('product' => $product);
    }
}

... простой (но в будущем более сложный) шаблон для контроллера продукта:

{# src/Acme/StoreBundle/Resources/views/Product/show.html.twig #}
{{ product.name }}

Итак, если я использую:

{% include "StoreBundle:Product:show.html.twig" with { product: product } %}

... все в порядке: 147 мс и 4608 Кб памяти.

Но когда мне нужен контроллер для отображения продукта:

{% render "StoreBundle:Product:show" with { product: product } %#}

... мой сценарий потребляет слишком много времени и памяти: 3639 мс и 17664 КБ памяти!

Как увеличить скорость и уменьшить потребление памяти с помощью контроллера?


person George    schedule 31.01.2012    source источник
comment
Вы находитесь в режиме разработки или разработки? Разница может быть удивительной.   -  person Louis-Philippe Huberdeau    schedule 31.01.2012
comment
Я использовал режим разработчика. Когда попробовал включить prod mode, то был удивлен - приложение шло очень быстро.   -  person George    schedule 01.02.2012
comment
Dev ведет много журналов и отключил самые важные кеши. Вы должны попытаться сравнить dev и prod с xdebug, чтобы увидеть, какие изменения происходят внутри. Это может уменьшить желание оптимизировать такие вещи в будущем.   -  person Louis-Philippe Huberdeau    schedule 01.02.2012


Ответы (2)


Каждый вызов рендеринга порождает новый запрос с описанной вами проблемой снижения производительности. Я не думаю, что с этим можно что-то сделать, кроме использования кеширования esi, чтобы можно было кэшировать отдельные фрагменты, поступающие из вызовов рендеринга. В противном случае вы можете попытаться пересмотреть свою логику, чтобы уменьшить использование вызовов рендеринга.

person Aldo Stracquadanio    schedule 31.01.2012
comment
Но все же удивительно, что один запрос с include занимает 147 мс / 4,5 МБ, а запрос, который использует render один раз (и, таким образом, также порождает только один подзапрос, который не должен занимать более 147 мс), занимает 4000 мс / 17,5 МБ. Прямо сейчас у нас есть та же проблема в проекте, но со взрывом использования памяти, например 150 МБ (~ 6 подзапросов). - person flu; 21.10.2013

Поправьте меня, если я ошибаюсь, но основная идея заключается в том, чтобы включить в основном копипастирование его содержимого вместо команды.

В то время как команда рендеринга должна сначала создать контроллер, инициализировать его, запустить соответствующую функцию и т. Д. Итак, кто знает, какая тяжелая артиллерия спрятана внутри этого контроллера или родительских классов, конструкторов и т. Д.?

Также помните, что отображаются даже включенные шаблоны. Таким образом, вы даже можете получить рекурсию или что-то подобное при рендеринге из twig. Лично я стараюсь избегать рендеринга чего-либо, кроме возврата контроллера.

Кроме того, как упоминал Луи-Филипп Хубердо в комментариях, среда разработки может сильно отличаться от режима prod из-за различных опций и ведения журнала.

Что касается советов - старайтесь избегать добавления логики в свои шаблоны или попробуйте использовать статические объекты, которые часто используются в шаблонах, для их повторного использования вместо того, чтобы создавать новые снова и снова. И рендеринг только с контроллеров

person GodlyHedgehog    schedule 07.03.2017