异步兼容性#

同步和异步代码在直接兼容性上存在差异,因为函数的调用方式取决于代码类型。这限制了可以执行的操作,例如 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.formrender_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))