2012-01-31 21 views
9

Estoy creando una tienda en línea. Tengo un problema de rendimiento si uso la función twig "renderizar" en lugar de "incluir".Twig: render vs include

Aquí está el código que muestra un catálogo de productos: Controlador

catálogo:

<?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, 
     )); 
    } 
} 

... plantilla para controlador de catálogo:

{# 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 %} 

... controlador de producto:

<?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); 
    } 
} 

... plantilla simple (pero más compleja en el futuro) para el controlador del producto:

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

Así que si uso:

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

... todo muy bien: 147ms y la memoria 4608Kb.

Pero cuando necesito un controlador para ver el producto:

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

... mi guión consume demasiado tiempo y la memoria: 3639ms y la memoria 17664Kb!

Cómo aumentar la velocidad y reducir el consumo de memoria mediante el uso del controlador?

+6

¿Está en modo dev o prod? La diferencia puede ser sorprendente. –

+2

Utilicé el modo "dev". Cuando traté de modo "prod", me sorprendió, la aplicación fue muy rápida. – George

+9

Dev realiza una gran cantidad de registros y tiene caches más importantes deshabilitados. Intente comparar dev y prod con xdebug para ver el tipo de cambios que se producen internamente.Podría reducir el impulso de optimizar tales cosas en el futuro. –

Respuesta

4

Cada llamada de renderización genera una nueva solicitud, con el problema de degradación del rendimiento que está describiendo. No creo que haya mucho que puedas hacer al respecto, sino que uses el almacenamiento en caché de esi, para que los fragmentos individuales provenientes de las llamadas de renderización se puedan almacenar en caché. De lo contrario, podría intentar revisar su lógica para reducir el uso de llamadas de renderizado.

+0

Pero todavía es sorprendente que una solicitud con 'include' tome 147ms/4.5MB y una solicitud que usa' render' una vez (y así también genera una sub-solicitud que no debe tomar más de 147ms) tome 4000ms/17.5 MEGABYTE. Tenemos el mismo problema en un proyecto en este momento pero con explosiones de uso de memoria como 150MB (~ 6 subpeticiones). – flu

0

Corrígeme si me equivoco, pero la idea básica es que incluya básicamente "copiar y pegar" su contenido en lugar del comando.

Considerando que el comando de renderizado debe crear primero el controlador, inicializarlo, ejecutar la función correspondiente, etc. Entonces, ¿quién sabe qué artillería pesada está oculta dentro de las clases, constructores y demás de este controlador o padre?

Recuerde también que incluso las plantillas incluidas se procesan. Así que incluso puede obtener recursiones o algo similar cuando renderiza desde ramitas. Personalmente trato de evitar representar algo que esté fuera del retorno del controlador.

Más como se menciona por Louis-Philippe Huberdeau en los comentarios, el entorno de desarrollo puede diferir drásticamente del modo prod debido a las diferentes opciones y el registro.

En cuanto a los consejos, trate de evitar poner lógica en sus controladores, o intente usar objetos estáticos que a menudo se usan en los controladores para reutilizarlos en lugar de crearlos una y otra vez. Y procesar cosas desde los controladores solo