Flask 的异步调用方法
Posted
技术标签:
【中文标题】Flask 的异步调用方法【英文标题】:Async call method with Flask 【发布时间】:2018-06-20 07:18:10 【问题描述】:我正在尝试通过 Flask 方法调用阻塞函数,但它需要几秒钟,所以我想我可以做一些异步调用来加快速度,但它没有按预期工作。 显然使用 asyncio 我不能只在后台启动协程而不等待执行结束,也许我需要使用线程?或者使用 grequest 作为我的阻塞函数正在使用请求...
到目前为止,这是我的代码:
@app.route("/ressource", methods=["GET"])
def get_ressource():
do_stuff()
return make_response("OK",200)
def do_stuff():
# Some stuff
fetch_ressource()
async def fetch_ressource():
return await blocking_function()
def blocking_function():
# Take 2-3 seconds
result = request.get('path/to/remote/ressource')
put_in_database(result)
我听说过 Celeri,但它似乎只对一个功能有点矫枉过正。
【问题讨论】:
【参考方案1】:现在回答有点晚了,但我对此很感兴趣。
我通过包装函数并通过asyncio.run()
调用它来管理它,但我不知道多个asyncio.run()
调用是否是一件好事。
from functools import wraps
from flask import Flask
import asyncio
def async_action(f):
@wraps(f)
def wrapped(*args, **kwargs):
return asyncio.run(f(*args, **kwargs))
return wrapped
app = Flask(__name__)
@app.route('/')
@async_action
async def index():
await asyncio.sleep(2)
return 'Hello world !'
app.run()
【讨论】:
这将禁用协程的所有优点。如果说有两个请求调用索引页,flask 会处理第二个请求,直到第一个请求完成,在正确使用协程的情况下,我们可以同时处理第二个请求和第一个请求。【参考方案2】:您可以使用 Quart 和 AIOHTTP 执行此操作,代码应该非常熟悉给定的 Flask 代码,
@app.route("/ressource", methods=["POST"])
async def get_ressource():
asyncio.ensure_future(blocking_function())
return await make_response("OK", 202)
async def blocking_function():
async with aiohttp.ClientSession() as session:
async with session.get('path/to/remote/ressource') as resp:
result = await resp.text()
await put_in_database(result)
注意:我已将其更改为 POST 路由,因为它正在执行某些操作,并且我已返回 202 响应以表明它已触发处理。
如果您希望坚持使用 Flask,我建议您使用 eventlet 并使用不包含 async
或 await
的 spawn(blocking_function)
。
还要注意我是 Quart 作者。
【讨论】:
是的,这通常是一个帖子,我在工作的 sn-p 中误用了一个 get。我有点害怕只为一个函数更改我的所有框架(即使它似乎几乎是相同的语法),我要试试 eventlet! 在烧瓶进程中执行异步代码不是很糟糕吗?【参考方案3】:阻塞函数在做什么?
使用 grequest 可行吗?
import grequests
@app.route('/do', methods = ['POST'])
def do():
result = grequests.map([grequests.get('slow api')])
return result[0].content
【讨论】:
我的阻塞函数通过请求获取一些资源(所以是的,可以在这里使用 grequest),然后将其保存在数据库中,如果我使用 grequest,db 中的所有保存也将是异步的? 这里的问题是我的客户端必须等待慢速api的响应才能有响应。 我想没有多少解决方案...如果前进的唯一可能性是从缓慢的 API 中获得答案... API 是罪魁祸首。你可以在上面加糖(可爱的加载图像,类似的 UX/UI 魔法)但是......最后你会等待,对吧?如果您不想使用像 Celery 这样更复杂的其他解决方案,我会尝试 grequests。测试会很快,你会明白这条路是否适合你。【参考方案4】:考虑使用 Sanic 框架,它的设计考虑到了异步操作,你可以看到 sanic 版本的代码here
【讨论】:
以上是关于Flask 的异步调用方法的主要内容,如果未能解决你的问题,请参考以下文章