asyncio.get_event_l oop () выдает ошибку, когда FLASK_DEBUG = 1 - PullRequest
2 голосов
/ 26 февраля 2020

У меня есть приложение flask, которое близко следует за приложением для рендеринга fast.ai: https://github.com/render-examples/fastai-v3. Он использует asyncio для загрузки модели при отображении страницы. Следующий код устанавливает его:

loop = asyncio.get_event_loop()
tasks = [asyncio.ensure_future(setup_learner())] #setup_learner downloads the model
learn = loop.run_until_complete(asyncio.gather(*tasks))[0]
loop.close()

Я заметил, что когда FLASK_DEBUG = 1, первая строка выдает ошибку:

RuntimeError: Нет текущего события l oop в потоке 'Thread-1'.

Но когда FLASK_DEBUG = 0, это не так. Но приложение сложнее отладить. Кто-нибудь сталкивался с этой проблемой и чем она вызвана?

1 Ответ

2 голосов
/ 26 февраля 2020

Причина, по которой это работает с FLASK_DEBUG=0, но не FLASK_DEBUG=1, заключается в том, что приложение работает в основном потоке, когда он не находится в режиме отладки, но не запускается в основном потоке, когда находится в режиме отладки.

Соответствующий код находится в asyncio.events.BaseDefaultEventLoopPolicy.get_event_l oop:

def get_event_loop():
    if (self._local._loop is None and
            not self._local._set_called and
            isinstance(threading.current_thread(), threading._MainThread)):
        self.set_event_loop(self.new_event_loop())

    if self._local._loop is None:
        raise RuntimeError('There is no current event loop in thread %r.'
                           % threading.current_thread().name)

    return self._local._loop

Событие l oop может быть создано только в главном потоке с текущей политикой события l oop: _UnixDefaultEventLoopPolicy в моем случае. Обратите внимание, что _UnixDefaultEventLoopPolicy подклассы BaseDefaultEventLoopPolicy, но не переопределяет BaseDefaultEventLoopPolicy.

Возможные решения:

  1. Создать новое событие l oop в текущем потоке loop = asyncio.new_event_loop()
  2. Создание пользовательской политики l oop, которая позволяет asyncio.get_event_loop() создавать новое событие l oop в потоке, отличном от основного, путем переопределения метода events.AbstractEventLoopPolicy.get_event_loop. Вероятно, самый безопасный способ сделать это - создать подкласс любой политики l oop, используемой вашей средой, и переопределить ее метод get_event_loop, удалив проверку основного потока. Таким образом вы сохраняете все другие варианты поведения политики, хотя изменение может нарушить некоторые из этих вариантов поведения.

В любом случае вы создаете событие l oop для потока. Мой стандартный наклон к go для простоты, поэтому # 1.

Так почему же приложение не запускается в основном потоке в режиме отладки? Во-первых, в режиме отладки есть два процесса: сервер Flask и отладчик flask run и python pydevd.py соответственно. Основной поток каждого процесса имеет событие l oop, которое, среди прочего, облегчает связь между сервером приложений и отладчиком и порождает другой поток, в котором фактически выполняется приложение. Вы также увидите это поведение без включенного режима отладки, если приложение обслуживается многопоточным сервером приложений, например gunicorn или uwsgi.

Flask на самом деле не поддерживает asyncio. Конечно, можно использовать его с Flask, но никаких гарантий относительно их совместимости не дается. См. Этот выпуск , а более конкретно: вопрос, упомянутый в его комментариях

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...