我想在每次执行Flask路由时执行一个异步函数。为什么abar
函数从未执行过
import asyncio
from flask import Flask
async def abar(a):
print(a)
loop = asyncio.get_event_loop()
app = Flask(__name__)
@app.route("/")
def notify():
asyncio.ensure_future(abar("abar"), loop=loop)
return "OK"
if __name__ == "__main__":
app.run(debug=False, use_reloader=False)
loop.run_forever()
我还尝试将阻塞调用放在单独的线程中。但是它仍然没有调用abar
函数
import asyncio
from threading import Thread
from flask import Flask
async def abar(a):
print(a)
app = Flask(__name__)
def start_worker(loop):
asyncio.set_event_loop(loop)
try:
loop.run_forever()
finally:
loop.close()
worker_loop = asyncio.new_event_loop()
worker = Thread(target=start_worker, args=(worker_loop,))
@app.route("/")
def notify():
asyncio.ensure_future(abar("abar"), loop=worker_loop)
return "OK"
if __name__ == "__main__":
worker.start()
app.run(debug=False, use_reloader=False)
您的错误是在调用
app.run()
之后尝试运行asyncio事件循环。后者不返回,而是运行Flask开发服务器事实上,这就是大多数WSGI设置的工作方式;主线程将忙于调度请求,或者Flask服务器作为WSGI服务器中的模块导入,并且您也不能在这里启动事件循环
相反,您必须在单独的线程中运行asyncio事件循环,然后通过^{} 在该单独的线程中运行协程。请参阅文档中的Coroutines and Multithreading section了解这需要什么
下面是一个模块的实现,该模块将运行这样一个事件循环线程,并提供实用程序来计划在该循环中运行的协程:
您可以使用此处定义的} instance 控制协同程序:
run_coroutine()
函数来调度异步IO例程。使用返回的^{Future.result()
获取结果。你可以给它一个超时;如果在超时时间内未产生任何结果,则协同程序将自动取消李>.cancelled()
、.running()
和.done()
方法查询协同程序的状态李>run_coroutine()
的线程)李>对于您的特定示例,
abar()
不返回任何结果,您可以忽略返回的未来,如下所示:请注意,在Python3.8之前的中,您不能使用在单独线程上运行的事件循环来创建子流程!请参阅我对Python3 Flask asyncio subprocess in route hangs的回答,了解Python 3.8
ThreadedChildWatcher
类的后端口对于你的问题,一个更简单的解决方案(在我有偏见的观点中)是从Flask切换到Quart。如果是这样,您的代码片段将简化为
如其他答案中所述,Flask应用程序运行被阻塞,并且不与asyncio循环交互。另一方面,Quart是基于asyncio构建的FlaskAPI,因此它应该按照您所期望的方式工作
作为更新,Flask Aiohttp不再是maintained
您可以将一些异步功能合并到Flask应用程序中,而无需将它们完全转换为asyncio
这将阻止Flask响应,直到异步函数返回,但它仍然允许您做一些聪明的事情。我使用这个模式使用aiohttp并行执行了许多外部请求,当它们完成后,我又回到传统的flask中进行数据处理和模板呈现
相关问题 更多 >
编程相关推荐