Сделайте неблокирующий запрос с запросами при запуске Flask с Gunicorn и Gevent

Приложение My Flask получит запрос, выполнит некоторую обработку и затем отправит запрос на медленную внешнюю конечную точку, на которую требуется ответить 5 секунд. Похоже, что запуск Gunicorn с Gevent позволит ему обрабатывать многие из этих медленных запросов одновременно. Как изменить приведенный ниже пример, чтобы представление не блокировалось?

import requests

@app.route('/do', methods = ['POST'])
def do():
    result = requests.get('slow api')
    return result.content
gunicorn server:app -k gevent -w 4

Ответы

Ответ 1

Сначала немного фона, блокирующий сокет является сокетом по умолчанию, как только вы начинаете читать свое приложение или поток, не восстанавливает контроль до тех пор, пока данные не будут прочитаны, или вы отсоедините. Это как python-requests, работает по умолчанию. Существует отключение, называемое grequests, которое обеспечивает неблокирующие чтения.

Основная механическая разница заключается в том, что send, recv, connect и accept может вернуться, ничего не сделав. У вас (конечно) число выбора. Вы можете проверить код возврата и коды ошибок и в целом свести себя с ума. Если вы не верите мне, попробуйте что-нибудь время

Источник: https://docs.python.org/2/howto/sockets.html

Далее также говорится:

Нет никаких сомнений в том, что самый быстрый код сокетов использует неблокирующие и выберите их мультиплексирование. Вы можете собрать что-то который будет насыщать подключение к локальной сети без каких-либо ЦПУ. Проблема в том, что приложение, написанное таким образом, не может сделать большую часть ничего другого - он должен быть готов к перемещению байтов вообще раз.

Предполагая, что ваше приложение действительно должно делать что-то большее, чем что нить является оптимальным решением

Но вы хотите добавить много сложностей в ваш взгляд, создав им собственные потоки. В частности, когда артиллерист как асинхронные рабочие?

Доступны асинхронные рабочие люди на основе Greenlets (через Eventlet и Gevent). Гринлеты - это реализация совлокальных многопоточность для Python. В общем, приложение должно быть в состоянии использовать эти рабочие классы без изменений.

и

Некоторые примеры поведения, требующие асинхронных работников: Приложения делая длинные блокирующие вызовы (т.е. внешние веб-службы)

Итак, чтобы сократить длинную историю, ничего не меняйте! Просто пусть это будет. Если вы внесете какие-либо изменения, пусть это будет ввести кэширование. Подумайте, используя Cache-control расширение, рекомендуемое разработчиками python-запросов.

Ответ 2

Если вы развертываете приложение Flask с помощью gunicorn, оно уже не блокирует. Если клиент ожидает ответа от одного из ваших представлений, другой клиент может сделать запрос к тому же представлению без проблем. Будет несколько сотрудников для обработки нескольких запросов одновременно. Не нужно менять код, чтобы это работало. Это также касается почти всех вариантов развертывания Flask.

Ответ 3

Вы можете использовать grequests. Он позволяет запускать другие зелени во время запроса. Он совместим с библиотекой requests и возвращает объект requests.Response. Используется следующее:

import grequests

@app.route('/do', methods = ['POST'])
def do():
    result = grequests.map([grequests.get('slow api')])
    return result[0].content

Изменить: я добавил тест и увидел, что время не улучшилось с помощью grequests, так как рабочий из-за выстрела из-под пулеметчика уже выполняет патч обезьяны при его инициализации: https://github.com/benoitc/gunicorn/blob/master/gunicorn/workers/ggevent.py#L65