2012-01-31 3 views
9

Sto creando un negozio online. Ho un problema di prestazioni se uso la funzione twig "render" invece di "include".Twig: render vs include

Ecco il codice che mostra un catalogo prodotti: Controller

catalogo:

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

... modello per il regolatore di catalogo:

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

... regolatore di prodotto:

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

... semplice (ma più complesso in futuro) modello per il controller di prodotto:

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

Quindi, se io uso:

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

... tutto ok: 147ms e la memoria 4608Kb.

Ma quando ho bisogno di un controller per visualizzare il prodotto:

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

... il mio script consuma troppo tempo e della memoria: 3639ms e la memoria 17664Kb!

Come aumentare la velocità e ridurre il consumo di memoria utilizzando il controller?

+6

Sei in modalità dev o prod? La differenza può essere sorprendente. –

+2

Ho usato la modalità "dev". Quando ho provato a "prod", sono rimasto sorpreso - l'applicazione è stata molto veloce. – George

+9

Dev esegue molte registrazioni e ha disabilitato le cache più importanti. Dovresti provare a confrontare dev e prod con xdebug per vedere il tipo di modifiche che avvengono internamente.Potrebbe ridurre l'urgenza di ottimizzare tali cose in futuro. –

risposta

4

Ogni chiamata di rendering genera una nuova richiesta, con il problema di degrado delle prestazioni che si sta descrivendo. Non penso che ci sia molto da fare in proposito, ma usando il caching esi, in modo che i singoli frammenti provenienti dalle chiamate di rendering possano essere memorizzati nella cache. Altrimenti potresti provare a rivedere la tua logica per ridurre l'utilizzo delle chiamate di rendering.

+0

Ma è comunque sorprendente che una richiesta con 'include' richiede 147 ms/4,5 MB e una richiesta che utilizza' render' una volta (e quindi genera anche solo una richiesta secondaria che non dovrebbe richiedere più di 147 ms) occupa 4000 ms/17,5 MB. Abbiamo lo stesso problema in un progetto in questo momento, ma con esplosioni di utilizzo della memoria come 150 MB (~ 6 sottoquest). – flu

0

Correggimi se ho torto, ma l'idea di base è che includa fondamentalmente "copia-incolla" il suo contenuto anziché il comando.

Mentre il comando di rendering deve prima creare il controller, inizializzarlo, eseguire la funzione corrispondente ecc. Quindi chissà quale artiglieria pesante è nascosta all'interno delle classi, dei costruttori e così via di questo controllore o genitore?

Ricorda anche che anche i modelli inclusi sono resi. Quindi potresti persino ottenere ricorsioni o qualcosa di simile quando esegui il rendering da un ramoscello. Personalmente cerco di evitare di eseguire rendering al di fuori del ritorno del controller.

Plus come menzionato da Louis-Philippe Huberdeau nei commenti, l'ambiente di sviluppo può differire drasticamente dalla modalità di produzione a causa di diverse opzioni e registrazione.

Per quanto riguarda i consigli, provare a evitare di inserire la logica nei controller o provare a utilizzare oggetti statici che vengono spesso utilizzati nei controller per riutilizzarli invece di crearne di nuovi più e più volte. E renderizza roba solo dai controllori