异步兼容性#
同步和异步代码在直接兼容性上存在差异,因为函数的调用方式取决于代码类型。这限制了可以执行的操作,例如 Quart 与 Flask 扩展的交互方式以及 Flask 直接异步化的任何努力。
在我看来,在 Python 中,从异步代码库调用同步代码比反过来更容易。我将在下面尝试解释原因。
从异步函数调用同步代码#
这通常很容易,因为您可以直接调用,或者通过简单的包装器等待同步函数。
async def example():
sync_call()
await asyncio.coroutine(sync_call)()
虽然这实际上并没有改变本质,调用仍然是同步的,但它确实可以工作。
从同步函数调用异步代码#
这是困难的地方,因为只能创建一个事件循环。因此,这只能使用一次。
def example():
loop = asyncio.get_event_loop()
loop.run_until_complete(async_call())
因此,如果您不在最外层范围,从同步函数调用异步代码实际上是不可能的。
在处理 Flask 扩展时,这存在问题,因为扩展可能包含类似以下代码:
@app.route('/')
def route():
data = request.form
return render_template_string("{{ name }}", name=data['name'])
虽然路由函数可以使用 asyncio.coroutine
函数包装并等待,但没有(简单?)方法可以在 request.form
和 render_template
调用之前插入 await
。
正因为如此,Quart-Flask-Patch 为 Flask 扩展创建了同步包装版本。前者添加了同步请求方法,后者提供了同步函数。
Quart 将一个 sync_wait
方法修补到基本事件循环上,允许以下定义:
from quart.templating import render_template as quart_render_template
def render_template(*args):
return asyncio.sync_wait(quart_render_template(*args))