我正在计划使用Twisted,Storm和Jinja使用Python的讨论软件。问题是Jinja不是用于Twisted或异步套接字库的,并且使用Twisted提供的性能是为什么我不打算使用Flask。我怎样才能用扭曲的Jinja?
那么,我该如何使用Jinja Twisted渲染网页?
我正在计划使用Twisted,Storm和Jinja使用Python的讨论软件。问题是Jinja不是用于Twisted或异步套接字库的,并且使用Twisted提供的性能是为什么我不打算使用Flask。我怎样才能用扭曲的Jinja?
那么,我该如何使用Jinja Twisted渲染网页?
您可以使用Jinja渲染网页,就像使用Twisted中的任何其他Python库一样。你只需要调用它。这对Twisted来说可以很好地工作,但如果Jinja做了一些阻塞操作,你可能会遇到性能问题。请注意,它可能是使用Twisted的阻塞库就好了,要么通过deferToThread
,要么只是阻止主循环,如果它不是性能问题。所以,我推断你的问题实际上是关于如何在不阻塞的情况下使用Jinja。
Jinja是一个模板库,这意味着它读取模板,调用模板上的某些视图逻辑,并编写一些HTML输出。因此,有三样东西,可以阻止:
我不知道神社,所以我不知道每个这些东西的API究竟是如何构成,我不能告诉你该怎么做,但我的猜测是那部分很容易;所以,我会给你一个关于第三方模板库和Twisted的一般答案。
所以我会满足每个这些问题,虽然不是很依次是:
实在是最合理的事情在这里做的是不关心它。阅读模板可能非常快。这些是经常访问的小文件,您的操作系统几乎可以保存在文件系统缓存中。除非你把它们放在NFS上,否则你不会阻止他们阅读它们。如果你分析你的应用程序并发现这是一个问题 - 因为,假设你的磁盘或远程文件系统速度非常慢 - 只需在启动时将模板读入cStringIO
或类似的东西,并在此之后将其提供给jinja。
的网页是不是所有的大,而且扭曲不提供阻止API写插槽。相反,它提供了一个API,它只是将整个结果缓存在内存中,直到它可以被写出。我的建议是,在阅读模板时做的事与此基本相同:除非您的输出量非常大,否则在向客户端回复响应时烧掉一点RAM可能就不错了。
这是你最有可能遇到的问题所在辖区。 Jinja可能不会处理Deferred
的结果。但实际上,Jinja并不会直接给你带来问题:它是Storm。当你访问某些属性时,Storm希望能够阻止,进行数据库查询。与数据库块交谈,这是在大多数Web应用程序中阻止I/O最显着的来源。所以你需要决定你将如何处理这个问题。你有几个选择:
deferToThread
调用(或类似)中预先获取风暴中的所有内容,并确保Jinja只访问内存中的对象。通过这种方式,您可以在主线程中运行渲染器,在执行数据库I/O的Deferred
上执行回调。如果你只是访问内存中的对象,你的渲染器仍然可能需要一点时间,但没关系。这个问题促使我转到post an article to my blog about the distinction between "blocking" and "running",这已经被搁置了很长一段时间了。你可能想要阅读它。如果以上选项均不适合您,Twisted has included a templating library that does support Deferred
s自版本11.0起。您可以考虑使用twisted.web.template
作为Jinja的替代方案。
我觉得龙卷风模板系统(它像Jinja2的模板,因为它是一个Django样...)可以在不龙卷风单独使用:
我们试图清理代码库,以减少相互依存在模块之间,所以您应该(理论上)能够在您的项目中独立使用任何模块,而无需使用整个软件包。
这里是如何实现的解决方案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)
你能在此展开:“神社是不是扭曲或异步发套接字库“? Jinja并没有说明你如何/在哪里使用它,所以声明(和这个问题)让我感到困惑。 –
事实上没有提到它与Twisted或任何异步套接字框架兼容,并且它使用了阻塞函数,这对于Twisted来说是不允许的。 – TeamBlast
不是一个模板库吗?为什么它会使用阻塞函数,或者确实使用它自己的I/O?如果你可以将它转储到内存缓冲区中,它应该没问题。 – Glyph