Почему метод 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
toTrue
в 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
toFalse
в конфигурации вашего приложения (это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.