Gunicorn gevent: В теме нет текущего события l oop - PullRequest
1 голос
/ 23 марта 2020

У меня есть приложение, использующее asyn c io для выполнения параллельных запросов к различным службам. Это приложение flask, работающее с Gunicorn.

К сожалению, некоторые запросы довольно длинные (до 10 с). До сих пор я использовал базового работника из Gunicorn (syn c), но, поскольку они являются конечным числом, у меня иногда заканчиваются их.

Так что я слышал о рабочем классе gevent, который для большинства запросов позволяет мне обрабатывать параллельно, но я не понимаю, как я должен иметь дело с кодом, используя asyncio. Я воспроизвел свою проблему на этом простом примере:

Я использую эту команду для запуска сервера:

gunicorn test_wsgi:app --config=test_wsgi_config.py

С test_wsgi.py:

import asyncio

from flask import Flask

app = Flask(__name__)


async def a_long_task():
    await asyncio.sleep(5)


@app.route('/')
def hello():
    loop = asyncio.get_event_loop()

    loop.run_until_complete(
        loop.create_task(a_long_task())
    )

    return f'Hello, world'

И test_wsgi_config.py

worker_class = "gevent"

Когда я использую worker_class = syn c, он работает нормально, но все запросы помещаются в очередь. Но с gevent у меня остается:

RuntimeError: There is no current event loop in thread 'DummyThread-1'

Если я создаю событие l oop:

@app.route('/')
def hello():
    asyncio.set_event_loop(asyncio.new_event_loop())
    loop = asyncio.get_event_loop()

    loop.run_until_complete(
        loop.create_task(a_long_task())
    )

    return f'Hello, world'

, я получаю:

RuntimeError: This event loop is already running

Когда я сделать несколько команд, как эта:

curl 127.0.0.1:8000 &

Я не уверен, как я должен справиться с этим.

1 Ответ

0 голосов
/ 23 марта 2020

Мне удалось заставить ваш пример работать, внеся небольшое изменение в способ получения вашего события l oop:

import asyncio

from flask import Flask

app = Flask(__name__)


async def a_long_task():
    await asyncio.sleep(5)


@app.route('/')
def hello():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)

    loop.run_until_complete(
        loop.create_task(a_long_task())
    )

    return f'Hello, world'

Это работает, потому что мы получаем новое событие l oop, которое должно всегда работать, а затем установить его в качестве текущего.

...