2012-02-07 21 views
13

Digamos que tengo una página con una galería de fotos. Cada miniatura tiene, p. una foto, país, autor, etc. Represento estos elementos/widgets usando etiquetas de plantilla (que cargan plantillas especificadas), va de esa manera por DRY (utilizo estos elementos/widgets por separado en diferentes lugares de la página).Django: renderizar muchas plantillas usando templatetags es muy lento

Y es muy lento.

He realizado algunos perfiles usando Django-debug-barra de herramientas:

SQL Queries: default 84.81 ms (147 queries) 

Pero:

Total CPU time: 5768.360 msec 

cual es demasiado tiempo para esperar.

Después de algunos análisis, resultó que el principal culpable es la creación de plantillas enginge.

Cuando quiero mostrar, p. 150 fotos, 600 elementos/widgets asociados se están procesando a través de plantillas. Significa 600 operaciones de E/S o incluso más. Mover estos widgets a la plantilla principal resuelve el problema, pero no lo mantiene SECO.

Así que mi pregunta es cómo se puede evitar tal comportamiento? ¿Ser SECO y lento o no SECO y rápido? Prefiero estar seco y rápido ...

+0

¿Puedes proporcionar el código templatetag? –

+0

El tiempo dedicado a las consultas es relativamente pequeño. Pero ORM tarda mucho más tiempo en generar esas consultas y analizar los resultados en instancias modelo –

Respuesta

11

Después de varias horas de creación de perfiles y búsqueda ...

Gracias por su ayuda, pero en este caso me parece que la mejor solución hasta ahora es utilizar Template fragment caching:

Lo probé y ganado 70-80% de rendimiento de velocidad!

{% load cache %} 
{% cache 3600 mywidget_id %} 
    .. rendered mywidget is cached .. 
{% endcache %} 
10

Es posible que desee probar el caching template loader, django.template.loaders.cached.Loader - sin duda debe reducir la cantidad de IO es necesario.

Edite para agregar Debe tener cuidado de suponer que solo porque se pasa la mayor parte del tiempo en la fase de representación de la plantilla, no se debe culpar al conteo de consultas. No olvide que los conjuntos de consulta son flojos y, a menos que los corte específicamente o los itere en la vista, solo se evaluarán cuando se cargue la plantilla. Yo diría que la reducción de su número de consultas a través del buen uso de select_related y otras técnicas debería ser de gran ayuda.

+0

Gracias. Lo redujo a 5054.582 mseg, que es ~ 11% de ganancia. Sin embargo, todavía demora 5 segundos en renderizar. ¿Qué más se puede hacer aquí? – laszchamachla

+1

¿Cómo funciona en la carga de la 2da página? –

+0

Lo mismo - 5 segundos es un mínimo. – laszchamachla

4

Supongo que, como está utilizando la barra de herramientas de depuración, está obteniendo estos números en desarrollo. Sin embargo, debido a esto, estos no son números "reales".

la incorporada en el servidor de Django es bueno para el desarrollo, pero tiene una serie de deficiencias que hacen que sea mucho más más lento que un verdadero servidor web sería. En primer lugar, tiene un único hilo, por lo que no significa que haya solicitudes paralelas. Esto también significa que las operaciones IO son discretas. En segundo lugar, tiene la tarea de no solo enviar solicitudes a Django, sino también recursos estáticos.

Largo y corto, si realmente quiere perfilar su sitio para los tiempos de carga de la página, tendrá que instalar un servidor web verdadero localmente. Básicamente configúrelo como lo haría en su entorno de producción. Estaría dispuesto a apostar que los tiempos de solicitud serán ahora mejor, entonces.

+1

Una nota, ya que Django 1.4, de ejecución del servidor se enhebra por lo que puede manejar las solicitudes paralelas – Izkata

0

Esto podría no aplicarse a este problema en particular, pero en algunos casos me ayudó a usar select_related en las consultas. Puede que no sea el caso, pero podría reducir el número de consultas.

+0

select_related no es algo para tirar de un conjunto de consultas 84 mS. Esto es sobre plantillas. – jstaab

0

El tiempo dedicado a las consultas es relativamente poco. Pero ORM tarda mucho más tiempo en generar estas consultas y analizar los resultados en las instancias del modelo.

Así, a pesar de gran número de consultas que su aplicación está limitada por la CPU debido al lento ORM (en su caso, puede tomar un segundo). Por lo tanto, debe reducir el número de consultas de todos modos.

más probable es que las consultas se realizan en el interior de su etiqueta de plantilla. Por lo tanto, debe obtener los datos deseados en algunas consultas y configurarlos en las instancias de fotos.

{% for photo in photos|annotate_comment_count %} 
    ... 
{% endfor %} 

def annotate_comment_count(photo_list): 
    counts = dict(Comment.objects.filter(photo__in=photo_list).values('photo') \ 
           .annotate(count=models.Count('id'))) 
    for photo in photo_list: 
     photo.comments_count = counts[photo.pk] 
    return photo_list 

Así, dentro de su templatetag que no tiene que consultar cuentan los comentarios de una sola foto, pero ya tiene esta información en comments_count atributo. Y lo lograste en una consulta.

0

que tenían el mismo problema, y ​​tal vez por la misma razón. Optimicé el rendimiento de una etiqueta de plantilla personalizada. El número de solicitudes de db cayó de 640 a 2, y el tiempo de db resultante fue inferior a 20 ms. ¡Mi página, sin embargo, se había vuelto más lenta! 7s -> 10s. Suspiro. Probé un cargador de plantillas en caché, sin efecto.

había renunciado, desactivada la barra de depuración de Django, después de lo cual el tiempo de respuesta se redujo a 1,2 segundos, increíble !! En mi caso, ¡el enorme tiempo de respuesta solo fue causado por la barra de herramientas de depuración! Se puede encontrar un problema relacionado here. No profundizo en este tema de la barra de herramientas, ya que estaba planeando guardar en caché la etiqueta de la plantilla utilizando el almacenamiento en caché de fragmentos de plantilla. Durante el desarrollo tengo 10 segundos de respuesta cada 15 minutos, con los que puedo vivir. De todos modos, espero que esto ayude.