简体   繁体   English

如何配置Jinja2模板?

[英]How to profile a Jinja2 template?

The Flask app I am profiling spends a long time rendering its Jinja2 templates. 我正在分析的Flask应用程序花费很长时间来渲染其Jinja2模板。

I have installed flask lineprofilerpanel which is interesting but unfortunately does not let me drill down into the template rendering to see where all the time is spent. 我已经安装了flask lineprofilerpanel这很有意思,但遗憾的是我不会深入到模板渲染中查看所有时间花在哪里。

What is the best way to profile a Jinja2 template? 分析Jinja2模板的最佳方法是什么?

Great question. 好问题。 I don't normally have much use for a profiler so this was a good excuse to learn. 我通常不太习惯使用剖析器,所以这是学习的好借口。 Following the example here: https://docs.python.org/2/library/profile.html#module-cProfile I coded up a simple example of profiling a jinja template. 按照这里的例子: https//docs.python.org/2/library/profile.html#module-cProfile我编写了一个简单的分析jinja模板的例子。

import cProfile as profile
import pstats
import StringIO

import jinja2
import time

pr = profile.Profile()

def slow():
    time.sleep(2)
    return "Booga!"

template = jinja2.Template(r'''
    {% for i in RANGE1 %}<h1>hello world {{ i}}</h1>{% endfor %}
    {% for i in RANGE2 %}<h1>foo bar {{ i}}</h1>{% endfor %}
    {{ SLOW() }}
        '''
        )

# here is the bit we want to profile
pr.enable()
context = {"RANGE1": range(1000000), "RANGE2":range(100), "SLOW":slow}
template.render(context)
pr.disable()


s = StringIO.StringIO()
ps = pstats.Stats(pr, stream=s).sort_stats("cumulative")
ps.print_stats()
print(s.getvalue())

Here is a snippet of the report: 以下是报告的片段:

         1000130 function calls in 2.448 seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    2.438    2.438 /usr/local/lib/python2.7/dist-packages/jinja2/environment.py:974(render)
        1    0.122    0.122    2.438    2.438 {method 'join' of 'unicode' objects}
  1000104    0.315    0.000    2.317    0.000 <template>:5(root)
        1    0.000    0.000    2.002    2.002 /usr/local/lib/python2.7/dist-packages/jinja2/runtime.py:169(call)
        1    0.000    0.000    2.002    2.002 profilej.py:10(slow)
        1    2.002    2.002    2.002    2.002 {time.sleep}
        2    0.010    0.005    0.010    0.005 {range}
        1    0.000    0.000    0.000    0.000 /usr/local/lib/python2.7/dist-packages/jinja2/environment.py:1015(new_context)
        1    0.000    0.000    0.000    0.000 /usr/local/lib/python2.7/dist-packages/jinja2/runtime.py:55(new_context)
        1    0.000    0.000    0.000    0.000 /usr/local/lib/python2.7/dist-packages/jinja2/runtime.py:115(__init__)
        3    0.000    0.000    0.000    0.000 {hasattr}
        1    0.000    0.000    0.000    0.000 /usr/local/lib/python2.7/dist-packages/jinja2/_compat.py:59(<lambda>)
        1    0.000    0.000    0.000    0.000 /usr/local/lib/python2.7/dist-packages/jinja2/nodes.py:81(__init__)
        3    0.000    0.000    0.000    0.000 {getattr}
        3    0.000    0.000    0.000    0.000 /usr/local/lib/python2.7/dist-packages/jinja2/runtime.py:149(resolve)
        1    0.000    0.000    0.000    0.000 /usr/local/lib/python2.7/dist-packages/jinja2/runtime.py:126(<genexpr>)
        1    0.000    0.000    0.000    0.000 {callable}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.000    0.000    0.000    0.000 {method 'iteritems' of 'dict' objects}
        1    0.000    0.000    0.000    0.000 {isinstance}

As I said I don't have much experience interpreting the output of profilers but I think in this example you can see the program spends a little over 2 seconds on time.sleep as expected, which is called by slow(). 正如我所说,我没有太多经验来解释分析器的输出,但我认为在这个例子中你可以看到程序在time.sleep上花了2秒多的时间,正如预期的那样,由slow()调用。 The rest of the of the time is taken up by join. 剩下的时间由加入占用。 I assume that is how Jinja2 processes my two for loops. 我认为这就是Jinja2如何处理我的两个for循环。

Adapting this example into a flask application shouldn't be too hard, just add the profiling bit around the template generation step and write the report to a file. 将此示例调整为烧瓶应用程序应该不会太难,只需在模板生成步骤周围添加分析位并将报告写入文件。 Perhaps you could even extract your templates from the web application and profile them outside of flask. 也许您甚至可以从Web应用程序中提取模板并将其分析到烧瓶外。

I hope this is helpful. 我希望这是有帮助的。

For a multi-threaded application like a running Flask server I find that the usual Python profiling tools aren't that great. 对于像运行Flask服务器这样的多线程应用程序,我发现通常的Python分析工具并不是那么好。

I have had good results with yappi which was designed for multithreaded apps. 我使用专为多线程应用程序设计的yappi取得了不错的成绩。 It's pretty straightforward: 这非常简单:

import yappi
yappi.start()

   [.. do stuff ..]

yappi.stop()
yappi.convert2pstats(yappi.get_func_stats()).dump_stats('myfile.pstats')

That saves profile data in a pstats compatible file so you can inspect it interactively in python: 这将配置文件数据保存在pstats兼容文件中,因此您可以在python中以交互方式检查它:

>>> import pstats 
>>> s = pstats.Stats('myfile.pstats')
>>> s.strip_dirs().sort_stats('cumtime').print_stats()

If you want to be clever you can put the start() bit and the stop() bit in Flask handlers so you can hit a URL to start profiling, drive your app, then hit a different URL to stop profiling and write out the stats file. 如果你想聪明一点,你可以在Flask处理程序中放置start()位和stop()位,这样你就可以点击一个URL来开始分析,驱动你的应用程序,然后点击另一个URL来停止分析并写出统计数据文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM