Flask 中的速度优化
Speed optimisation in Flask
我的项目 (Python 2.7) 包含一个屏幕抓取程序,它每天收集一次数据,提取有用的内容并将其存储在几个 pickle 中。使用 Flask/Ninja 将泡菜渲染到 HTML 页面。所有这些都有效,但是当 运行 它在我的本地主机 (Windows 10) 上时,它相当慢。我计划在 PythonAnywhere 上部署它。
该站点还有一个关于页面。关于页面的内容是一个降价文件,我在每次编辑后使用 markdown2
将其转换为 HTML。关于模板加载 HTML,像这样:
{% include 'about_content.html' %}
这比让 Flask-Markdown
渲染关于文本(就像我最初那样)加载 多 快:
{% filter markdown %}
{% include 'about_content.md' %}
{% endfilter %}
那么现在。我有点担心部署网站时主页加载速度不够快。内容每天只更新一次,如果您刷新主页,则无需重新渲染任何内容。所以我想知道我是否可以对 about-content 做一个类似的技巧:
我可以让 Flask 在渲染 pickles 之后将结果保存为 html,然后从部署的站点提供该结果吗?或者我可以调用一些浏览器模块,保存它的输出并提供它吗?或者这完全是个坏主意,我不应该担心因为 Flask 在现实生活中的服务器上速度非常快吗?
关于渲染的问题
您实际上可以使用 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
,则无需呈现。
EDIT 注意 @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
Flask 还有一个选项,您可以在其中启用多线程。
app.run(threaded=True)
2018 年 11 月 11 日更新
- 可以考虑使用Redis store。每当发生使旧模板无效的事情时,请清除特定文件的缓存。在再次生成模板之前首先查看 Redis 存储(模板渲染很可能需要您从数据库中读取数据。内存中的缓存存储要快得多,因此您可以从 Redis 缓存中受益)
- 存储呈现的文件并使用 CDN 提供服务。因此,每次客户端请求该特定模板时,它都已经存储在 CDN 上,根本不会触及您的 Flask 服务器。您可以编写逻辑,如果 CDN 上不存在文件或内容,它应该回退到您的 Flask 服务器。您只需要确保一个策略,这样您就不会在 CDN 上拥有过时的数据。
我的项目 (Python 2.7) 包含一个屏幕抓取程序,它每天收集一次数据,提取有用的内容并将其存储在几个 pickle 中。使用 Flask/Ninja 将泡菜渲染到 HTML 页面。所有这些都有效,但是当 运行 它在我的本地主机 (Windows 10) 上时,它相当慢。我计划在 PythonAnywhere 上部署它。
该站点还有一个关于页面。关于页面的内容是一个降价文件,我在每次编辑后使用 markdown2
将其转换为 HTML。关于模板加载 HTML,像这样:
{% include 'about_content.html' %}
这比让 Flask-Markdown
渲染关于文本(就像我最初那样)加载 多 快:
{% filter markdown %}
{% include 'about_content.md' %}
{% endfilter %}
那么现在。我有点担心部署网站时主页加载速度不够快。内容每天只更新一次,如果您刷新主页,则无需重新渲染任何内容。所以我想知道我是否可以对 about-content 做一个类似的技巧:
我可以让 Flask 在渲染 pickles 之后将结果保存为 html,然后从部署的站点提供该结果吗?或者我可以调用一些浏览器模块,保存它的输出并提供它吗?或者这完全是个坏主意,我不应该担心因为 Flask 在现实生活中的服务器上速度非常快吗?
关于渲染的问题
您实际上可以使用 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
,则无需呈现。
EDIT 注意 @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
Flask 还有一个选项,您可以在其中启用多线程。
app.run(threaded=True)
2018 年 11 月 11 日更新
- 可以考虑使用Redis store。每当发生使旧模板无效的事情时,请清除特定文件的缓存。在再次生成模板之前首先查看 Redis 存储(模板渲染很可能需要您从数据库中读取数据。内存中的缓存存储要快得多,因此您可以从 Redis 缓存中受益)
- 存储呈现的文件并使用 CDN 提供服务。因此,每次客户端请求该特定模板时,它都已经存储在 CDN 上,根本不会触及您的 Flask 服务器。您可以编写逻辑,如果 CDN 上不存在文件或内容,它应该回退到您的 Flask 服务器。您只需要确保一个策略,这样您就不会在 CDN 上拥有过时的数据。