2011-11-04 5 views
3

Je planifie un logiciel de discussion en utilisant Python avec Twisted, Storm et Jinja. Le problème est que Jinja n'était pas fait pour les bibliothèques de socket Twisted ou asynchrones, et les performances fournies en utilisant Twisted est pourquoi je ne prévois pas d'utiliser Flask. Alors, comment puis-je avoir des pages web de rendu Twisted utilisant Jinja?Comment utiliser Jinja avec Twisted?

+2

Pouvez-vous à ce sujet: « Jinja n'a pas été fait pour Twisted ou asynchrone bibliothèques de socket "? Jinja ne dicte pas comment/où vous l'utilisez, alors cette déclaration (et cette question) me confond. –

+0

Le fait qu'il n'y ait aucune mention de sa compatibilité avec Twisted ou tout cadre de socket asynchrone, et qu'il utilise des fonctions de blocage, qui sont un non-non pour Twisted. – TeamBlast

+1

Est-ce que jinja n'est pas une bibliothèque de templates? Pourquoi utiliserait-il des fonctions de blocage ou, en fait, ferait-il ses propres E/S? Si vous pouvez le vider dans un tampon mémoire, ça devrait aller. – Glyph

Répondre

15

Vous pouvez afficher des pages Web à l'aide de Jinja de la même manière que toute autre bibliothèque Python dans Twisted. Vous appelez juste dedans. Cela fonctionnera bien avec Twisted, bien que vous puissiez rencontrer des problèmes de performance si Jinja fait quelque chose qui bloque. Notez qu'il est possible d'utiliser des bibliothèques de blocage avec Twisted très bien, soit via deferToThread ou simplement en bloquant le mainloop si ce n'est pas un problème de performance. Donc, je déduis que votre question est vraiment sur la façon d'utiliser Jinja sans bloquer.

Jinja est une bibliothèque de modèles, ce qui signifie qu'elle lit un modèle, appelle une logique de vue sur le modèle et écrit une sortie HTML. Donc, il y a 3 choses qui peuvent bloquer:

  1. lecture du modèle,
  2. écrit le résultat.
  3. exécutant la logique de vue (votre code d'application),

Je ne sais pas Jinja, donc je ne sais pas exactement comment les API pour chacune de ces choses est structuré et je ne peux pas vous dire que faire, mais je suppose que cette partie est facile; donc, je vais vous donner une réponse générale sur les bibliothèques de modèles tiers et Twisted.

Je vais répondre à chacune de ces préoccupations, bien que pas tout à fait dans l'ordre:

1. Lecture du modèle

vraiment faire ici la chose la plus raisonnable est de ne pas soucier. La lecture du modèle est probablement très rapide. Ce sont de minuscules fichiers fréquemment consultés, que votre système d'exploitation garde presque certainement dans son cache de système de fichiers. Il est peu probable que vous alliez les bloquer en les lisant à moins que vous ne fassiez quelque chose d'insensé comme les mettre sur NFS. Si vous profilez votre application et trouvez que c'est un problème - parce que, disons, vous avez des disques extrêmement lents ou un système de fichiers distant - il suffit de lire le modèle dans un cStringIO ou quelque chose de similaire au moment du démarrage.

3. Écrire la réponse

pages Web ne sont pas tout ce que grand, et Twisted ne fournit pas une API de blocage pour écrire à des prises. Au lieu de cela, il offre une API qui tampon tout le résultat en mémoire jusqu'à ce qu'il puisse être écrit. Ma suggestion est de faire essentiellement la même chose ici qu'avec la lecture du template: à moins que vous ayez une énorme sortie, il est probablement bon de graver un peu de RAM pendant que la réponse est envoyée au client.

2. Exécution de votre vue logique

C'est la région où vous êtes le plus susceptible de se heurter à des problèmes. Jinja ne gère probablement pas les résultats de Deferred s. Mais en fait, ce n'est pas Jinja qui va vous donner directement des problèmes: c'est Storm. Storm s'attend à être capable de bloquer, de faire des requêtes de base de données, lorsque vous accédez à certains attributs. Parler aux blocs de la base de données, et c'est la source la plus importante d'E/S de blocage dans la plupart des applications Web.Vous devez donc décider comment vous allez gérer cela. Vous avez quelques options:

  1. Il suffit de le faire dans le fil principal et ne vous inquiétez pas à ce sujet. Peut-être que votre application est pour un groupe de travail de 10 personnes et que votre base de données est locale. Bien sûr, votre E/S va bloquer, mais si elle répond toujours à ses exigences de performance, qui s'en soucie? Toutes les applications ne doivent pas nécessairement évoluer vers la Lune et vers l'arrière. Pré-extraire tout de la tempête dans un appel deferToThread (ou similaire) et assurez-vous que Jinja n'accède qu'aux objets en mémoire. De cette façon, vous pouvez exécuter vos moteurs de rendu dans votre thread principal, dans un rappel sur un Deferred qui effectuait des E/S de base de données. Si vous n'accédez qu'aux objets en mémoire, votre moteur de rendu peut encore prendre un peu de temps, mais ça va. Cette question m'a incité à post an article to my blog about the distinction between "blocking" and "running" qui traînait comme un brouillon depuis un certain temps; vous voudrez peut-être aller le lire.
  2. Effectuez tout votre rendu dans un thread ou un sous-processus et traitez-le comme un composant bloquant de votre programme. Cela perd certains des avantages de l'utilisation de Twisted, mais c'est toujours une stratégie parfaitement viable d'intégrer un composant Jinja/Storm bloquant et un composant pur-Twist non bloquant, la partie relayant le message de chat.

Si aucune de ces options ne fonctionne pour vous, Twisted has included a templating library that does support Deferreds depuis la version 11.0. Vous pouvez envisager d'utiliser twisted.web.template comme alternative à Jinja.

0

Je pense que le système de modèle Tornado (il est comme le modèle Jinja2 car il est un Django comme ...) peut être utilisé sans la tornade elle-même:

Nous avons essayé de nettoyer la base de code pour réduire les interdépendances entre les modules, vous devriez (théoriquement) être capable d'utiliser n'importe lequel des modules indépendamment dans votre projet sans utiliser le paquet entier.

Tornado Templates

2

est par exemple exemple ici sur la façon de mettre en œuvre la solution 3, avec l'aide de la fonction de retour différé de base:

from jinja2 import Template 
from twisted.internet import threads, reactor, defer 

def inThread(f): 
    def new_f(*args, **kwargs): 
     return threads.deferToThread(f, *args, **kwargs) 
    return new_f 


def fromThread(f): 
    def new_f(*args, **kwargs): 
     return threads.blockingCallFromThread(reactor, lambda: defer.maybeDeferred(f, *args, **kwargs)) 
    return new_f 


class DeferredTemplate(Template): 
    def render(self, **kw): 
     hooked_kw = {} 
     for k, v in kw.iteritems(): 
      # decorate the callable so that they are run in the main thread 
      if callable(v): 
       v = fromThread(v) 
      hooked_kw[k] = v 
     return inThread(Template.render)(self, **hooked_kw) 

from twisted.trial import unittest 
class TestJinjaDeferred(unittest.TestCase): 
    @defer.inlineCallbacks 
    def test_basic(self): 
     def getHello(): 
      d = defer.Deferred() 
      reactor.callLater(0.0, lambda: d.callback("Hello")) 
      return d 

     def getWorldSync(): 
      return "world" 

     template = DeferredTemplate("{{ getHello() }} {{ getWorldSync() }}") 
     res = yield template.render(getHello=getHello, getWorldSync=getWorldSync) 
     self.assertEqual(u"Hello world", res)