我怎样才能将Jinja与Twisted一起使用?

时间:2021-11-11 00:42:26

I'm planning up a discussion software using Python with Twisted, Storm, and Jinja. The problem is that Jinja was not made for Twisted or asynchronous socket libraries, and the performance provided by using Twisted is why I don't plan on using Flask.

我正在计划使用Python与Twisted,Storm和Jinja的讨论软件。问题是Jinja不是用于Twisted或异步套接字库,而使用Twisted提供的性能是我不打算使用Flask的原因。

So, how can I have Twisted render webpages using Jinja?

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

3 个解决方案

#1


15  

You can render web pages using Jinja the same way you would use any other Python library in Twisted. You just call into it. This will work fine with Twisted, although you may run into performance issues if Jinja does something blocking. Note that it is possible to use blocking libraries with Twisted just fine, either via deferToThread or just blocking the mainloop if it's not a performance problem. So, I am inferring that your question is really about how to use Jinja without blocking.

您可以使用Jinja呈现网页,就像在Twisted中使用任何其他Python库一样。你只需要打电话给它。这将适用于Twisted,但如果Jinja阻止了某些事情,你可能会遇到性能问题。请注意,可以通过deferToThread使用带有Twisted的阻塞库,或者只是阻止主循环,如果它不是性能问题。所以,我推断你的问题实际上是关于如何使用Jinja而不阻止。

Jinja is a templating library, which means that it reads a template, invokes some view logic on the template, and writes some HTML output. So there are 3 things that can block:

Jinja是一个模板库,这意味着它会读取模板,在模板上调用一些视图逻辑,并编写一些HTML输出。所以有3件事可以阻止:

  1. reading the template,
  2. 阅读模板,
  3. writing the result.
  4. 写出结果。
  5. running the view logic (your application code),
  6. 运行视图逻辑(您的应用程序代码),

I don't know Jinja, so I don't know exactly how the APIs for each of these things is structured and I can't tell you what to do, but my guess is that that part's easy; so, I'm going to give you a general answer about 3rd-party templating libraries and Twisted.

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

So I'll address each of these concerns, although not quite in order:

所以我会解决这些问题,尽管不是很顺序:

1. Reading the Template

Really the most reasonable thing to do here is to not care about it. Reading the template is probably really fast. These are frequently-accessed, tiny files, which your operating system is almost certainly keeping in its filesystem cache. It's unlikely that you're ever going to block on reading them unless you're doing something nuts like putting them on NFS. If you profile your application and find that this is a problem – because, let's say, you have extremely slow disks or a remote filesystem – just read the template into a cStringIO or something similar at startup time and feed it to jinja after that.

在这里做的最合理的事情是不关心它。阅读模板可能非常快。这些是经常访问的小文件,您的操作系统几乎肯定会保留在其文件系统缓存中。除非你把它们放在NFS上做一些疯狂的事情,否则你不太可能会阻止阅读它们。如果您对应用程序进行概要分析并发现这是一个问题 - 因为,假设您有极慢的磁盘或远程文件系统 - 只需在启动时将模板读入cStringIO或类似内容,然后将其提供给jinja。

3. Writing the Response

Web pages are not all that big, and Twisted doesn't provide a blocking API to write to sockets. Instead, it offers an API which just buffers the whole result in memory until it can be written out. My suggestion is to do basically the same thing here as with reading the template: unless you have seriously huge output, it's probably fine to burn up a little bit of RAM while the response is being fed to the client.

网页并不是那么大,Twisted没有提供阻塞API来写入套接字。相反,它提供了一个API,它只是将整个结果缓冲到内存中,直到可以写出来。我的建议是在这里做与阅读模板基本相同的事情:除非你有非常大的输出,否则在响应被送到客户端时可能会烧掉一点RAM。

2. Running your View Logic

This is the area where you are most likely to run into problems. Jinja probably doesn't handle the results of Deferreds. But actually, it's not actually Jinja which is going to give you problems directly: it's Storm. Storm expects to be able to block, to make database queries, when you access certain attributes. Talking to the database blocks, and this is the most signifiant source of blocking I/O in most web applications. So you need to decide how you're going to deal with that. You have a few options:

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

  1. Just do it in the main thread and don't worry about it. Maybe your application is for a workgroup of 10 people and your database is local. Sure, your I/O is going to block, but if it still meets its performance requirements, who cares? Not every application has to scale to the moon and back.
  2. 只需在主线程中执行它,不要担心它。也许您的应用程序适用于10人的工作组,您的数据库是本地的。当然,您的I / O会阻塞,但如果它仍然满足其性能要求,谁在乎呢?并非每个应用程序都必须缩放到月球和背部。
  3. Pre-fetch everything from storm in a deferToThread call (or similar) and make sure Jinja is only accessing objects in memory. This way you can run your renderers in your main thread, in a callback on a Deferred that was doing database I/O. If you're only accessing objects in memory, your renderer still might take a little while, but that's fine. This question prompted me to post an article to my blog about the distinction between "blocking" and "running" which had been hanging out as a draft for quite a while; you may want to go read it.
  4. 在deferToThread调用(或类似)中预先从storm中获取所有内容,并确保Jinja只访问内存中的对象。这样,您可以在主线程中运行渲染器,在执行数据库I / O的Deferred上进行回调。如果你只是访问内存中的对象,你的渲染器可能还需要一段时间,但这没关系。这个问题促使我在我的博客上发表了一篇关于“阻止”和“运行”之间区别的文章,这篇文章已经被搁置了很长一段时间;你可能想读它。
  5. Do your whole render in a thread or subprocess, and treat it as a blocking component of your program. This loses some of the benefits of using Twisted, but it's still a perfectly viable strategy to integrate a blocking Jinja/Storm component and a non-blocking pure-Twisted component, the actual chat-message relaying part.
  6. 在线程或子进程中完成整个渲染,并将其视为程序的阻塞组件。这会失去使用Twisted的一些好处,但它仍然是一个完全可行的策略,可以集成阻塞的Jinja / Storm组件和非阻塞的纯Twisted组件,即实际的聊天消息中继部分。

If none of these options work for you, Twisted has included a templating library that does support Deferreds since version 11.0. You may consider using twisted.web.template as an alternative to Jinja.

如果这些选项都不适合您,Twisted包含一个模板库,该版本支持自版本11.0以来的Deferreds。你可以考虑使用twisted.web.template作为Jinja的替代品。

#2


2  

Here is sample example on how to implement solution 3, with basic deferred returning function support:

以下是如何实现解决方案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)

#3


0  

i think Tornado template system (it's like the Jinja2 template since it's a Django-like...) can be used without the tornado itself:

我认为Tornado模板系统(它就像Jinja2模板,因为它是类似Django的......)可以在没有龙卷风本身的情况下使用:

We attempted to clean up the code base to reduce interdependencies between modules, so you should (theoretically) be able to use any of the modules independently in your project without using the whole package.

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

Tornado Templates

龙卷风模板

#1


15  

You can render web pages using Jinja the same way you would use any other Python library in Twisted. You just call into it. This will work fine with Twisted, although you may run into performance issues if Jinja does something blocking. Note that it is possible to use blocking libraries with Twisted just fine, either via deferToThread or just blocking the mainloop if it's not a performance problem. So, I am inferring that your question is really about how to use Jinja without blocking.

您可以使用Jinja呈现网页,就像在Twisted中使用任何其他Python库一样。你只需要打电话给它。这将适用于Twisted,但如果Jinja阻止了某些事情,你可能会遇到性能问题。请注意,可以通过deferToThread使用带有Twisted的阻塞库,或者只是阻止主循环,如果它不是性能问题。所以,我推断你的问题实际上是关于如何使用Jinja而不阻止。

Jinja is a templating library, which means that it reads a template, invokes some view logic on the template, and writes some HTML output. So there are 3 things that can block:

Jinja是一个模板库,这意味着它会读取模板,在模板上调用一些视图逻辑,并编写一些HTML输出。所以有3件事可以阻止:

  1. reading the template,
  2. 阅读模板,
  3. writing the result.
  4. 写出结果。
  5. running the view logic (your application code),
  6. 运行视图逻辑(您的应用程序代码),

I don't know Jinja, so I don't know exactly how the APIs for each of these things is structured and I can't tell you what to do, but my guess is that that part's easy; so, I'm going to give you a general answer about 3rd-party templating libraries and Twisted.

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

So I'll address each of these concerns, although not quite in order:

所以我会解决这些问题,尽管不是很顺序:

1. Reading the Template

Really the most reasonable thing to do here is to not care about it. Reading the template is probably really fast. These are frequently-accessed, tiny files, which your operating system is almost certainly keeping in its filesystem cache. It's unlikely that you're ever going to block on reading them unless you're doing something nuts like putting them on NFS. If you profile your application and find that this is a problem – because, let's say, you have extremely slow disks or a remote filesystem – just read the template into a cStringIO or something similar at startup time and feed it to jinja after that.

在这里做的最合理的事情是不关心它。阅读模板可能非常快。这些是经常访问的小文件,您的操作系统几乎肯定会保留在其文件系统缓存中。除非你把它们放在NFS上做一些疯狂的事情,否则你不太可能会阻止阅读它们。如果您对应用程序进行概要分析并发现这是一个问题 - 因为,假设您有极慢的磁盘或远程文件系统 - 只需在启动时将模板读入cStringIO或类似内容,然后将其提供给jinja。

3. Writing the Response

Web pages are not all that big, and Twisted doesn't provide a blocking API to write to sockets. Instead, it offers an API which just buffers the whole result in memory until it can be written out. My suggestion is to do basically the same thing here as with reading the template: unless you have seriously huge output, it's probably fine to burn up a little bit of RAM while the response is being fed to the client.

网页并不是那么大,Twisted没有提供阻塞API来写入套接字。相反,它提供了一个API,它只是将整个结果缓冲到内存中,直到可以写出来。我的建议是在这里做与阅读模板基本相同的事情:除非你有非常大的输出,否则在响应被送到客户端时可能会烧掉一点RAM。

2. Running your View Logic

This is the area where you are most likely to run into problems. Jinja probably doesn't handle the results of Deferreds. But actually, it's not actually Jinja which is going to give you problems directly: it's Storm. Storm expects to be able to block, to make database queries, when you access certain attributes. Talking to the database blocks, and this is the most signifiant source of blocking I/O in most web applications. So you need to decide how you're going to deal with that. You have a few options:

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

  1. Just do it in the main thread and don't worry about it. Maybe your application is for a workgroup of 10 people and your database is local. Sure, your I/O is going to block, but if it still meets its performance requirements, who cares? Not every application has to scale to the moon and back.
  2. 只需在主线程中执行它,不要担心它。也许您的应用程序适用于10人的工作组,您的数据库是本地的。当然,您的I / O会阻塞,但如果它仍然满足其性能要求,谁在乎呢?并非每个应用程序都必须缩放到月球和背部。
  3. Pre-fetch everything from storm in a deferToThread call (or similar) and make sure Jinja is only accessing objects in memory. This way you can run your renderers in your main thread, in a callback on a Deferred that was doing database I/O. If you're only accessing objects in memory, your renderer still might take a little while, but that's fine. This question prompted me to post an article to my blog about the distinction between "blocking" and "running" which had been hanging out as a draft for quite a while; you may want to go read it.
  4. 在deferToThread调用(或类似)中预先从storm中获取所有内容,并确保Jinja只访问内存中的对象。这样,您可以在主线程中运行渲染器,在执行数据库I / O的Deferred上进行回调。如果你只是访问内存中的对象,你的渲染器可能还需要一段时间,但这没关系。这个问题促使我在我的博客上发表了一篇关于“阻止”和“运行”之间区别的文章,这篇文章已经被搁置了很长一段时间;你可能想读它。
  5. Do your whole render in a thread or subprocess, and treat it as a blocking component of your program. This loses some of the benefits of using Twisted, but it's still a perfectly viable strategy to integrate a blocking Jinja/Storm component and a non-blocking pure-Twisted component, the actual chat-message relaying part.
  6. 在线程或子进程中完成整个渲染,并将其视为程序的阻塞组件。这会失去使用Twisted的一些好处,但它仍然是一个完全可行的策略,可以集成阻塞的Jinja / Storm组件和非阻塞的纯Twisted组件,即实际的聊天消息中继部分。

If none of these options work for you, Twisted has included a templating library that does support Deferreds since version 11.0. You may consider using twisted.web.template as an alternative to Jinja.

如果这些选项都不适合您,Twisted包含一个模板库,该版本支持自版本11.0以来的Deferreds。你可以考虑使用twisted.web.template作为Jinja的替代品。

#2


2  

Here is sample example on how to implement solution 3, with basic deferred returning function support:

以下是如何实现解决方案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)

#3


0  

i think Tornado template system (it's like the Jinja2 template since it's a Django-like...) can be used without the tornado itself:

我认为Tornado模板系统(它就像Jinja2模板,因为它是类似Django的......)可以在没有龙卷风本身的情况下使用:

We attempted to clean up the code base to reduce interdependencies between modules, so you should (theoretically) be able to use any of the modules independently in your project without using the whole package.

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

Tornado Templates

龙卷风模板