2012-01-31 13 views
9

Tworzę sklep internetowy. Mam problem z wydajnością, jeśli używam funkcji gałki "renderuj" zamiast "uwzględnij".Twig: render vs include

Oto kod, który wyświetla się w katalogu produktów: Kontroler

katalogowy:

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

... szablon dla kontrolera katalogowy:

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

... kontrolera produktu:

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

... proste (ale bardziej skomplikowane w przyszłości) szablon dla kontrolera produktu:

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

Więc jeśli mogę użyć:

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

... wszystko ok: 147ms i pamięć 4608Kb.

Ale kiedy potrzebny jest kontroler, aby wyświetlić produkt:

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

... mój skrypt pochłania zbyt dużo czasu i pamięci: 3639ms i pamięć 17664Kb!

Jak zwiększyć prędkość i zmniejszyć zużycie pamięci za pomocą kontrolera?

+6

Czy jesteś w trybie dewelopera lub prod? Różnica może być zaskakująca. –

+2

Użyłem trybu "dev". Kiedy próbowałem "prod" tryb, byłem zaskoczony - aplikacja była bardzo szybka. – George

+9

Dev robi dużo rejestrowania i ma najważniejsze pamięci podręczne wyłączone. Powinieneś spróbować porównać dev i prod z xdebug, aby zobaczyć zmiany zachodzące wewnętrznie.Może to zmniejszyć chęć optymalizacji takich rzeczy w przyszłości. –

Odpowiedz

4

Każde wywołanie renderowania powoduje utworzenie nowego żądania z opisywanym problemem degradacji wydajności. Nie sądzę, że można zrobić dużo, ale używając esi caching, aby pojedyncze fragmenty pochodzące z wywołań renderowania mogły być buforowane. W przeciwnym razie możesz spróbować poprawić logikę, aby zmniejszyć użycie wywołań renderujących.

+0

Ale wciąż jest zaskakujące, że jedna prośba z 'include' zajmuje 147ms/4.5MB, a żądanie, które używa' render'a raz (a więc również spawnuje tylko jedno pod-żądanie, które nie powinno zająć więcej niż 147ms) zajmuje 4000ms/17,5 MB. Mamy ten sam problem w projekcie w tej chwili, ale z wykorzystaniem pamięci takich jak 150 MB (~ 6 podań). – flu

0

Popraw mnie, jeśli się mylę, ale podstawową ideą jest to, że w zasadzie to "kopiuje-wkleja" swoją zawartość zamiast polecenia.

Podczas gdy komenda render musi najpierw utworzyć kontroler, zainicjować go, uruchomić odpowiednią funkcję itd. Kto więc wie, jaka ciężka artyleria jest ukryta wewnątrz klasy kontrolera lub rodzica, konstruktorów i tak dalej?

Pamiętaj również, że nawet zawarte szablony są renderowane. Więc możesz nawet uzyskać rekurencje lub coś podobnego podczas renderowania z gałązki. Osobiście staram się unikać renderowania czegokolwiek poza kontrolą kontrolera.

Plus, jak wspomniał Louis-Philippe Huberdeau w komentarzach, środowisko dev może drastycznie różnić się od trybu prod z powodu różnych opcji i logowania.

Jeśli chodzi o porady - unikaj umieszczania logiki w kontrolerach lub spróbuj użyć statycznych obiektów, które są często używane w kontrolerach do ponownego użycia zamiast tworzenia nowych w kółko. I renderuj rzeczy od kontrolerów tylko