我有一个紧跟 fast.ai 的渲染应用程序的 flask 应用程序: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: There is no current event loop in thread 'Thread-1'.
但是当 FLASK_DEBUG=0 时,它不会。但该应用程序更难调试。有没有人遇到过这个问题,是什么原因造成的?
最佳答案
这适用于 FLASK_DEBUG=0
的原因但不是 FLASK_DEBUG=1
是因为该应用程序在未处于 Debug模式时在主线程中运行,但在处于 Debug模式时不在主线程中运行。
相关代码在 asyncio.events.BaseDefaultEventLoopPolicy.get_event_loop 中:
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
事件循环只能在具有当前事件循环策略的主线程中创建:
_UnixDefaultEventLoopPolicy
就我而言。请注意 _UnixDefaultEventLoopPolicy
子类 BaseDefaultEventLoopPolicy
但不会覆盖 BaseDefaultEventLoopPolicy
.可能的解决方案:
loop = asyncio.new_event_loop()
asyncio.get_event_loop()
的自定义事件循环策略通过覆盖 events.AbstractEventLoopPolicy.get_event_loop
在主线程以外的线程中创建新的事件循环方法。最安全的方法可能是子类化您的环境正在使用的任何事件循环策略并覆盖其 get_event_loop
方法,去掉主线程检查。通过这种方式,您可以保留所有其他策略行为,但更改可能会破坏其中一些行为。 无论哪种方式,您都在为线程创建事件循环。我的标准倾向是追求简单,所以#1。
那么为什么在 Debug模式下应用程序不在主线程中运行?首先,在 Debug模式下运行时有两个进程:Flask 服务器和调试器,
flask run
和 python pydevd.py
, 分别。每个进程的主线程都有一个事件循环,用于促进应用服务器和调试器之间的通信——除其他外,并产生另一个实际运行应用的线程。如果应用程序由多线程应用程序服务器提供服务,您还将在未启用 Debug模式的情况下看到此行为,例如gunicorn 或 uwsgi。Flask 并不真正支持
asyncio
.当然可以将它与 Flask 一起使用,但不能保证它们的兼容性。看到这个 issue ,更具体地说:the issue referenced in its comments
关于debugging - asyncio.get_event_loop() 在 FLASK_DEBUG=1 时抛出错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60406696/