为什么烧瓶的jsonify方法很慢?

时间:2016-06-20 21:14:07

标签: python json performance api flask

我在烧瓶中写了一个返回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"

...该功能在.05秒左右完成。

有谁能告诉我为什么jsonify慢得多?返回原始Flask响应有什么问题吗?

3 个答案:

答案 0 :(得分:9)

我的猜测是:它与缩进和pretty json转储有很大关系。这是方法定义(我删除了注释以节省空间,可以找到完整的代码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']
    )
如果模块可用,则

dumpssimplejson.dumps,否则使用json.dumps

答案 1 :(得分:5)

jsonify()只包裹json.dumps()。但是,根据您的Flask应用程序的配置以及您正在使用的Flask版本,它可能会将indent=2separators=(', ', ': ')传递给json.dumps。 (如果您不熟悉这些论点,请参阅https://docs.python.org/3/library/json.html上的漂亮打印文档。)

传递这些参数会大大减慢json.dumps的速度。使用https://github.com/zemirco/sf-city-lots-json中的181MB citylots.json文件作为样本数据,这些漂亮的打印参数在我的MacBook Pro上将json.dumps()的运行时间从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_REGULARTrue(默认情况下为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']
    )

如果你在Flask 之前的版本到1.0,那么如果两者都发生漂亮打印:

  • 没有在您应用的配置中明确设置JSONIFY_PRETTYPRINT_REGULARFalse(默认情况下为True ),和
  • 当前请求不是XHR请求

在那些旧版本中,从来没有必要重新定义jsonify以消除漂亮的打印,因为您可以这样做:

app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False

(或者,如果您使用的是1.0版之前的Flask,并且只想禁用生产中的漂亮打印,那么就无需更改代码;相反,只需升级到最新版本的Flask。)

答案 2 :(得分:3)

我花了一段时间才弄清楚,但是Flask (xenial)vash@localhost:~/python/stack_overflow/test$ ls 1_file_b.py 2_file_e.py 3_file_a.py 4_file_c.py 5_file_d.py 在编码器上设置了jsonify参数,看来它默认为sort_keys

添加:

True

通过配置,我可以将大型JSON结构的速度提高7倍。