2016-09-28 6 views
16

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

Что вы ожидаете отсюда? Вы ничего не можете вернуть клиенту, если вы еще не получили его. –

+0

Я ожидал сделать его асинхронным, поэтому, когда он ждет супер медленного api, мощность процессора может использоваться для обработки других входящих запросов, которые могут потенциально к другому пути. (Поскольку я предполагаю, что это приложение получит много других разных входящих запросов) – JLTChiu

+1

Это не значит, что вы думаете, что это значит. И Gunicorn * должен * обрабатывать это для вас, вы можете проверить, чтобы убедиться, что просто добавив 'time.sleep (30)' там, я думаю. Это называется моделью реактора, но Gunicorn позволяет клиенту подключиться, а затем передает запрос работнику. Когда работник заканчивает работу, он возвращает данные от рабочего и затем возвращает их обратно в пул. Я не уверен, что он закручивает нового рабочего, если все существующие уже заняты. –

ответ

6

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

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

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

Он также продолжает говорить:

Там нет сомнений, что самый быстрый сокеты код использует неблокирующая и выберите их мультиплексирование. Вы можете собрать что-то , которое насытит подключение к локальной сети, не создавая нагрузки на CPU . Беда в том, что приложение, написанное таким образом, не может делать ничего из что-нибудь еще - оно должно быть готово к случайному перетасовке байтов раз.

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

Но вы хотите добавить целую кучу сложности вашей точки зрения, имея это порождение его собственной потоки. Особенно, когда стрельба async workers?

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

и

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

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

2

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

import grequests 

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

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

6

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

+0

В этом случае OP говорит о том, чтобы сделать другой блокирующий сетевой вызов из своего представления. Что отличается от сценария в вашем ответе. – e4c5

+0

ОП спросил: «Как изменить приведенный ниже пример, чтобы представление не блокировалось?» Представление уже не блокируется. Разумеется, блоки 'request.get', но это действие происходит таким образом, что другой клиент может получить доступ к одному и тому же представлению, что, по моему мнению, является основной проблемой OP. Вы также можете сделать апи-вызов неблокирующим, но это не помогает, потому что вы не сможете ничего вернуть клиенту до тех пор, пока он не завершится. – sytech

+0

Действительно? возможно, я неправильно понял этот вопрос. Я понимаю, что он хотел, чтобы запросы не блокировались. – e4c5