Почему метод jsonify flask медленный?

Я пишу API в колбе, которая возвращает json. Каждая функция колбы имеет вид

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 намного медленнее? Есть ли что-то неправильное в возвращении ответа сырой колбы вместо этого?

3 ответов


мое предположение: это имеет много общего с отступом и делает pretty дамп json. Вот определение метода (я удалил комментарии, чтобы сэкономить место, полный код можно найти здесь):

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() просто обтекает json.dumps(). Однако в зависимости от конфигурации вашего приложения Flask и используемой версии Flask он может пройти indent=2 и separators=(', ', ': ') to json.dumps. (См. документы по pretty-printing в https://docs.python.org/3/library/json.html если вы не знакомы с этими аргументами).

передача этих аргументов замедляется json.dumps резко. Используя 181MB citylots.json файл из https://github.com/zemirco/sf-city-lots-json в качестве примера данных эти аргументы pretty-printing увеличиваются json.dumps()время выполнения от 7 секунд до 31 секунды на моем MacBook Pro:

>>> 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

начиная с колбы 1.0, эта дорогостоящая pretty-printing произойдет, если или:

  • вы явно установлен JSONIFY_PRETTYPRINT_REGULAR to True в config вашего приложения (это False по умолчанию), или
  • вы запускаете приложение в режиме отладки

(вы можете увидеть эти условия в колбе 1.0.2 код https://github.com/pallets/flask/blob/1.0.2/flask/json/__init__.py#L309.)

если вы используете колбу > =1.0 и имеете (вероятно, необычную) необходимость отключить pretty-printing даже в debug режим, вы всегда сможете реализовать свой собственный jsonify путем копирования и вставки встроенного jsonifyопределение и удаление всей логики pretty-printing:

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']
    )

если вы находитесь в колбе версии до 1,0, то pretty-печать вместо этого происходит, если оба:

  • вы не явно установлен JSONIFY_PRETTYPRINT_REGULAR to False в конфигурации вашего приложения (это True по умолчанию), и
  • текущий запрос не является запросом XHR

в этих старых версиях никогда нет необходимости переопределять jsonify чтобы устранить pretty-printing, так как вы можете просто сделать:

app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False

(альтернативно, если вы используете версию колбы pre-1.0 и только хотите отключить pretty-printing в производстве, тогда нет необходимости менять код; вместо этого просто обновите до последней версии Flask.)


мне потребовалось некоторое время, чтобы понять, но фляга jsonify задает sort_keys аргумент на кодировщике, и кажется, что по умолчанию он True.

добавляем:

JSON_SORT_KEYS = False

к конфигурации дал мне скорость фактора 7 для больших структур JSON.