为啥flask的jsonify方法很慢?
Posted
技术标签:
【中文标题】为啥flask的jsonify方法很慢?【英文标题】:Why is flask's jsonify method slow?为什么flask的jsonify方法很慢? 【发布时间】:2016-10-22 06:20:36 【问题描述】:我正在烧瓶中编写一个返回 json 的 API。每个烧瓶函数的形式为
from flask import jsonify
@app.route('/getdata')
def get_data():
data = load_data_as_dict()
return jsonify(data)
如果我返回大量数据,调用此函数大约需要 1.7 秒。但是,如果我这样做:
from flask import Response
@app.route('/getdata')
def get_data():
data = load_data_as_dict()
data_as_str = json.dumps(data)
return Response(response=data_as_str, status=200, mimetype="application/json"
...函数在大约 0.05 秒内完成。
谁能告诉我为什么jsonify
这么慢?改为返回原始 Flask 响应有什么问题吗?
【问题讨论】:
【参考方案1】:我的猜测是:它与缩进和制作pretty
json 转储有很大关系。下面是方法定义(为了节省空间,我去掉了cmets,完整代码可以在here找到):
def jsonify(*args, **kwargs):
indent = None
separators = (',', ':')
if current_app.config['JSONIFY_PRETTYPRINT_REGULAR'] and not request.is_xhr:
indent = 2
separators = (', ', ': ')
if args and kwargs:
raise TypeError('jsonify() behavior undefined when passed both args and kwargs')
elif len(args) == 1: # single args are passed directly to dumps()
data = args[0]
else:
data = args or kwargs
return current_app.response_class(
(dumps(data, indent=indent, separators=separators), '\n'),
mimetype=current_app.config['JSONIFY_MIMETYPE']
)
如果模块可用,dumps
包装simplejson.dumps
,否则使用json.dumps
。
【讨论】:
确实如此,我试过了。如果你重新定义 jsonify 和 jsut 删除缩进,它会工作得更快。在我的测试中时间从 17s 变成了 0.1s,170 次!【参考方案2】:jsonify()
只是包装了json.dumps()
。但是,根据您的 Flask 应用程序的配置和您使用的 Flask 版本,它可能会将indent=2
和separators=(', ', ': ')
传递给json.dumps
。 (如果您不熟悉这些论点,请参阅https://docs.python.org/3/library/json.html 上关于漂亮打印的文档)。
传递这些参数会显着减慢json.dumps
。使用来自 https://github.com/zemirco/sf-city-lots-json 的 181MB citylots.json
文件作为示例数据,这些漂亮的打印参数将 json.dumps()
在我的 MacBook Pro 上的运行时间从 7 秒增加到 31 秒:
>>> import time
>>> import json
>>> citylots = json.load(open('citylots.json'))
>>> start = time.time(); x = json.dumps(citylots); print(time.time() - start)
7.165302753448486
>>> x = None
>>> start = time.time(); x = json.dumps(citylots, indent=2, separators=(', ', ': ')); print(time.time() - start)
31.19125771522522
从 Flask 1.0 开始,如果任一,就会发生这种昂贵的漂亮打印:
您已在应用的配置中明确将JSONIFY_PRETTYPRINT_REGULAR
设置为 True
(默认为 False
),或者
您正在调试模式下运行您的应用
(您可以在 https://github.com/pallets/flask/blob/1.0.2/flask/json/__init__.py#L309 的 Flask 1.0.2 代码中查看这些条件。)
如果您使用 Flask >=1.0 并且(可能不寻常)需要禁用漂亮打印即使在调试模式下,您始终可以通过复制和粘贴来实现自己的 jsonify
内置jsonify
的定义并删除所有漂亮的打印逻辑:
from flask import current_app
from json import dumps
def jsonify(*args, **kwargs):
if args and kwargs:
raise TypeError('jsonify() behavior undefined when passed both args and kwargs')
elif len(args) == 1: # single args are passed directly to dumps()
data = args[0]
else:
data = args or kwargs
return current_app.response_class(
dumps(data) + '\n',
mimetype=current_app.config['JSONIFY_MIMETYPE']
)
如果您使用的是 Flask1.0 之前的版本,那么如果两者都发生,则会发生漂亮的打印:
您还没有在应用的配置中将JSONIFY_PRETTYPRINT_REGULAR
明确设置为False
(默认为True
),并且
当前请求不是 XHR 请求
在那些旧版本中,永远不需要重新定义 jsonify
来消除漂亮的打印,因为你可以这样做:
app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False
(或者,如果您使用的是 Flask 1.0 之前的版本,并且只想在生产中禁用漂亮打印,则无需更改代码;相反,只需升级到最新版本的 Flask。 )
【讨论】:
【参考方案3】:我花了一段时间才弄明白,但 Flask jsonify
在编码器上设置了 sort_keys
参数,它似乎默认为 True
。
添加:
JSON_SORT_KEYS = False
对于较大的 JSON 结构,配置使我的速度提高了 7 倍。
【讨论】:
哦,哇,这是我在回答中完全错过的一件大事!我可能会相应地更新我的。 请注意这一点,因为同一数据的不同排序可能会导致大量不必要的缓存未命中。以上是关于为啥flask的jsonify方法很慢?的主要内容,如果未能解决你的问题,请参考以下文章