【问题标题】:Speed optimisation in FlaskFlask 中的速度优化
【发布时间】:2017-02-08 20:40:21
【问题描述】:

我的项目 (Python 2.7) 包含一个屏幕抓取工具,它每天收集一次数据,提取有用的内容并将其存储在几个泡菜中。使用 Flask/Ninja 将泡菜渲染到 HTML 页面。所有这些都有效,但是在我的本地主机(Windows 10)上运行它时,它相当慢。我计划将它部署在 PythonAnywhere 上。

该网站还有一个关于页面。关于页面的内容是一个降价文件,我在每次编辑后使用markdown2 将其转换为 HTML。 about-template 加载 HTML,如下所示:

{% include 'about_content.html' %}

这比让Flask-Markdown 渲染 about-text(就像我一开始那样)更快地加载

{% filter markdown %}
{% include 'about_content.md' %}
{% endfilter %}

那么现在。我有点担心部署站点时主页加载速度不够快。内容每天仅更新一次,如果您刷新主页,则无需重新渲染任何内容。所以我想知道我是否可以做一个与 about-content 类似的技巧:

我可以让 Flask 在渲染泡菜后将结果保存为 html,然后从部署的站点提供该结果吗?或者我可以调用一些浏览器模块,保存它的输出并提供它吗?或者这完全是个坏主意,我不应该担心,因为 Flask 在现实生活中的服务器上快速缩放?

【问题讨论】:

    标签: python html flask jinja2


    【解决方案1】:

    关于渲染的问题

    您实际上可以使用 Jinja 做很多事情。可以随时运行 Jinja 并将其保存为 HTML 文件。这样,每次您发送文件请求时,它都不必再次呈现它。它只提供静态文件。

    这是一些代码。我的观点在它的一生中都不会改变。因此,一旦创建了视图,我就会创建一个静态 HTML 文件。

    from jinja2 import Environment, FileSystemLoader
    
    def example_function():
        '''Jinja templates are used to write to a new file instead of rendering when a request is received. Run this function whenever you need to create a static file'''
    
        # I tell Jinja to use the templates directory
        env = Environment(loader=FileSystemLoader('templates'))
        
        # Look for the results template
        template = env.get_template('results.html')
    
        # You just render it once. Pass in whatever values you need. 
        # I'll only be changing the title in this small example.
        output_from_parsed_template = template.render(title="Results")
    
        with open("/directory/where/you/want/to/save/index.html", 'w') as f:
            f.write(output_from_parsed_template)
    
    # Flask route
    @app.route('/directory/where/you/want/to/save/<path:path>')
    def serve_static_file(path):
        return send_from_directory("directory/where/you/want/to/save/", path)
    

    现在,如果您使用上述 URI localhost:5000/directory/where/you/want/to/save/index.html,则无需渲染。

    编辑注意@app.route 需要一个URL,所以/directory/where/you/want/to/save 必须从根开始,否则你会得到ValueError: urls must start with a leading slash。此外,您可以将呈现的页面与其他模板一起保存,然后将其路由如下,从而无需(并且与send_from_directory 一样快):

    @app.route('/')
    def index():
        return render_template('index.html')
    

    其他方式

    如果您想获得更好的性能,请考虑通过 gunicorn、nginx 等为您的 Flask 应用程序提供服务。

    Setting up nginx, gunicorn and Flask

    Don't use Flask built-in server in production

    Flask 还有一个选项可以启用多线程。

    app.run(threaded=True)
    

    2018 年 11 月 11 日更新

    • 您可以考虑使用 Redis 存储。每次发生使旧模板无效的事情时,请清除特定文件的缓存。在再次生成模板之前先查看 Redis 存储(模板渲染很可能需要您从数据库中读取数据。内存中的缓存存储要快得多,因此您可以从 Redis 缓存中受益)
    • 存储渲染文件并使用 CDN 提供服务。因此,每次客户端请求该特定模板时,它都会存储在 CDN 上,并且根本不会触及您的 Flask 服务器。你可以编写逻辑,如果文件或内容在 CDN 上不存在,它应该回退到你的 Flask 服务器。您只需确保制定策略,以免 CDN 上出现过时数据。

    【讨论】:

    • 顺便提一下。切勿在真实服务器(生产)上使用 Flask。 Flask 的创造者本人反对这个想法。 Flask 在现实生活中既不安全也不高效。如果您想在生产环境中部署它,请在 Flask 旁边使用 gunicorn 和 nginx。
    • 来自 PythonAnywhere 开发人员的简短说明(正如 OP 所说他们计划在我们的网站上部署)——我们使用 nginx 作为我们的前端 Web 服务器,因此您的 Flask 应用程序是安全且高效的.
    • @RolfBly 应该会减少你的工作量。使用 gunicorn 只需要 3 到 4 行附加代码。您还应该知道 gunicorn 不适用于 Windows(它仅适用于 unix)。在 PythonAnywhere 上部署时可以直接使用它。
    • @AbhirathMahipal 非常感谢!我让它按要求工作(见编辑)。我确实对你的app.route 有点挣扎。我想我需要阅读装饰器和 &lt;path:path&gt; 技巧。
    • @RolfBly 请注意,您必须使用 send_from_directory 发送文件。不要使用渲染模板。为什么要浪费时间(它会打开文件并搜索 Jinja 标记然后发送它)当我们已经知道它已经呈现时。抱歉打错了。我修正了我的答案:)
    猜你喜欢
    • 2021-09-20
    • 1970-01-01
    • 2011-08-01
    • 2016-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-17
    相关资源
    最近更新 更多