2011-11-04 56 views
3

我正在计划使用Twisted,Storm和Jinja使用Python的讨论软件。问题是Jinja不是用于Twisted或异步套接字库的,并且使用Twisted提供的性能是为什么我不打算使用Flask。我怎样才能用扭曲的Jinja?

那么,我该如何使用Jinja Twisted渲染网页?

+2

你能在此展开:“神社是不是扭曲或异步发套接字库“? Jinja并没有说明你如何/在哪里使用它,所以声明(和这个问题)让我感到困惑。 –

+0

事实上没有提到它与Twisted或任何异步套接字框架兼容,并且它使用了阻塞函数,这对于Twisted来说是不允许的。 – TeamBlast

+1

不是一个模板库吗?为什么它会使用阻塞函数,或者确实使用它自己的I/O?如果你可以将它转储到内存缓冲区中,它应该没问题。 – Glyph

回答

15

您可以使用Jinja渲染网页,就像使用Twisted中的任何其他Python库一样。你只需要调用它。这对Twisted来说可以很好地工作,但如果Jinja做了一些阻塞操作,你可能会遇到性能问题。请注意,它可能是使用Twisted的阻塞库就好了,要么通过deferToThread,要么只是阻止主循环,如果它不是性能问题。所以,我推断你的问题实际上是关于如何在不阻塞的情况下使用Jinja。

Jinja是一个模板库,这意味着它读取模板,调用模板上的某些视图逻辑,并编写一些HTML输出。因此,有三样东西,可以阻止:

  1. 阅读模板,
  2. 写的结果。
  3. 运行视图逻辑(应用程序代码),

我不知道神社,所以我不知道每个这些东西的API究竟是如何构成,我不能告诉你该怎么做,但我的猜测是那部分很容易;所以,我会给你一个关于第三方模板库和Twisted的一般答案。

所以我会满足每个这些问题,虽然不是很依次是:

1.读取模板

实在是最合理的事情在这里做的是不关心它。阅读模板可能非常快。这些是经常访问的小文件,您的操作系统几乎可以保存在文件系统缓存中。除非你把它们放在NFS上,否则你不会阻止他们阅读它们。如果你分析你的应用程序并发现这是一个问题 - 因为,假设你的磁盘或远程文件系统速度非常慢 - 只需在启动时将模板读入cStringIO或类似的东西,并在此之后将其提供给jinja。

3.编写响应

的网页是不是所有的大,而且扭曲不提供阻止API写插槽。相反,它提供了一个API,它只是将整个结果缓存在内存中,直到它可以被写出。我的建议是,在阅读模板时做的事与此基本相同:除非您的输出量非常大,否则在向客户端回复响应时烧掉一点RAM可能就不错了。

2.运行你的视图逻辑

这是你最有可能遇到的问题所在辖区。 Jinja可能不会处理Deferred的结果。但实际上,Jinja并不会直接给你带来问题:它是Storm。当你访问某些属性时,Storm希望能够阻止,进行数据库查询。与数据库块交谈,这是在大多数Web应用程序中阻止I/O最显着的来源。所以你需要决定你将如何处理这个问题。你有几个选择:

  1. 只要在主线程中做到这一点,不用担心。也许你的应用程序是针对一个由10人组成的工作组,而你的数据库是本地的。当然,你的I/O会阻止,但如果它仍然满足其性能要求,谁在乎?并非每个应用程序都必须缩放到月球和背面。
  2. deferToThread调用(或类似)中预先获取风暴中的所有内容,并确保Jinja只访问内存中的对象。通过这种方式,您可以在主线程中运行渲染器,在执行数据库I/O的Deferred上执行回调。如果你只是访问内存中的对象,你的渲染器仍然可能需要一点时间,但没关系。这个问题促使我转到post an article to my blog about the distinction between "blocking" and "running",这已经被搁置了很长一段时间了。你可能想要阅读它。
  3. 在线程或子进程中执行整个渲染,并将其视为程序的阻止组件。这失去了使用Twisted的一些好处,但它仍然是一个完全可行的策略,用于集成一个阻塞的Jinja/Storm组件和一个非阻塞的纯扭曲组件,即实际的聊天消息中继组件。

如果以上选项均不适合您,Twisted has included a templating library that does support Deferreds自版本11.0起。您可以考虑使用twisted.web.template作为Jinja的替代方案。

0

我觉得龙卷风模板系统(它像Jinja2的模板,因为它是一个Django样...)可以在不龙卷风单独使用:

我们试图清理代码库,以减少相互依存在模块之间,所以您应该(理论上)能够在您的项目中独立使用任何模块,而无需使用整个软件包。

Tornado Templates

2

这里是如何实现的解决方案3的样品例如,基本推迟返回功能支持:

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)