Блокировка Flask на конечной точке без разрешения вызовов другой конечной точки

Одна из конечных точек моего flask API делает длинный запрос к Live Stream. Вот пример кода:

@app.route('/stream')
def live_stream(sensor_id):
    stream = requests.get('stream_url', stream=True)
    return Response(stream_with_context(stream.iter_content(chunk_size=2048)),
                content_type=stream.headers['content-type'])

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

Я использую сервер gevent WSGI:

 http_server = WSGIServer(('0.0.0.0', 5000), app).serve_forever()

И я делаю запросы из шаблона, уже возвращенного маршрутом Flask.

Как я могу делать параллельные запросы к API, не застревая на этом?


person Miguel Andrade    schedule 12.02.2020    source источник
comment
Можете показать/описать, что происходит внутри stream_with_context?   -  person yorodm    schedule 12.02.2020
comment
stream_with_context — это метод Flask по умолчанию. Прямая трансляция работает, но я не могу делать больше запросов.   -  person Miguel Andrade    schedule 12.02.2020
comment
Вы исправили обезьяну, как указано здесь: stackoverflow.com/questions/14551823/   -  person Maurice Meyer    schedule 17.02.2020


Ответы (2)


Я никогда не использовал gevent, но если я правильно понимаю, у него есть однопоточный цикл обработки событий (как asyncio). Но мое понимание может быть неправильным.

Взгляните на этот ответ https://stackoverflow.com/a/19153826/

Когда у вас есть фрагмент кода Python, который выполняется долго (в течение нескольких секунд) и не вызывает переключения гринлетов, все другие задания гринлетов/гевентов будут «голодать» и не будут иметь времени вычислений, и это будет выглядеть как ваше приложение. висит».

Предлагаю выполнить одно из следующих действий:

  • Либо запустите свое веб-приложение на многопоточном сервере WSGI.
  • Или узнайте, есть ли у gevent сетевой клиент, который вы можете использовать вместо requests, основанного на грилетах.
  • Или запустите блокирующую часть вашего кода в инструменте потока.
  • Или вызовите from gevent import monkey; monkey.patch_all() в первую очередь в своем серверном коде и посмотрите, сделает ли это requests неблокирующим.
person codeape    schedule 14.02.2020
comment
Но модуль запросов не от Gevent. Это pypi.org/project/requests . Есть ли у вас какие-либо предложения для использования в качестве альтернативы Gevent? Он должен работать с ОС Windows. - person Miguel Andrade; 14.02.2020
comment
Попробуйте сначала использовать веб-сервер разработки flask. Вы можете передать аргумент app.run(), чтобы он работал в многопоточном режиме. - person codeape; 14.02.2020
comment
Работает фляжный сервер разработки! Есть ли у вас какие-либо идеи, как я могу настроить сервер eventlet WSGI на многопоточность? - person Miguel Andrade; 14.02.2020
comment
Я полагаю, что сервер событий WSGI является однопоточным сервером. Возможные варианты: использовать многопоточный сервер, выполнить сетевой запрос с использованием метода, основанного на гринлетах, или выполнить запрос в пуле потоков. - person codeape; 19.02.2020
comment
... добавлена ​​четвертая опция: проверить, делает ли gevent monkey-patching запросы неблокирующими. - person codeape; 21.02.2020
comment
@Miguel Andrade Поскольку мой ответ а) правильно определяет основную причину и б) предлагает несколько возможных решений, я предлагаю вам отметить его как принятый. - person codeape; 15.03.2020

Вы можете проверить, выполнив следующие действия:

  1. убедитесь, что ваш код monkey patched в самой первой строке (иначе, если какой-то модуль не исправлен и выполняет какую-то операцию ввода-вывода, ваше приложение заблокируется. Я помню, что в gevent есть API, который может проверить monkey.is_module_patched('request'));
  2. убедитесь, что вы не выполняете какую-либо задачу, связанную с ЦП (код, ограниченный ЦП, заблокирует ваш код);

Надеюсь, это поможет!

person panda912    schedule 08.03.2020