如何从 Quart 获取事件循环

Cra*_*ras 5 python python-asyncio goblin quart

你好,我对Python相当陌生,我正在尝试将Flask上的现有应用程序转换为Quart(https://gitlab.com/pgjones/quart),它应该构建在asyncio之上,所以我可以使用Goblin OGM 与 JanusGraph 或 TinkerPop 交互。根据我在 Goblin 上找到的示例,我需要获取一个事件循环来异步运行命令。

    >>> import asyncio
    >>> from goblin import Goblin

    >>> loop = asyncio.get_event_loop()
    >>> app = loop.run_until_complete(
    ...     Goblin.open(loop))
    >>> app.register(Person, Knows)
Run Code Online (Sandbox Code Playgroud)

然而,我找不到从 Quart 获取事件循环的方法,即使它是构建在 asyncio 之上的。

有谁知道我怎样才能得到它?任何帮助将不胜感激。

use*_*342 4

TL;DR 要获取事件循环,请调用asyncio.get_event_loop().

在基于 asyncio 的应用程序中,事件循环通常不属于 Quart 或任何其他协议/应用程序级组件,它由 asyncio 或可能是像 uvloop 这样的加速器提供。事件循环是通过调用 获得的asyncio.get_event_loop(),有时用 来设置asyncio.set_event_loop()

这就是 quartapp.run()用来运行应用程序的方式,这意味着它与 asyncio 为主线程创建的默认事件循环一起工作。run()在你的情况下,你可以在注册后简单地调用 quart Goblin

loop = asyncio.get_event_loop()
goblin_app = loop.run_until_complete(Goblin.open(loop))
goblin_app.register(Person, Knows)
quart_app = Quart(...)
# ... @app.route, etc

# now they both run in the same event loop
quart_app.run()
Run Code Online (Sandbox Code Playgroud)


上面应该回答了实际意义上的问题。但是,如果多个组件坚持使用自己的run()方法来旋转事件循环,则这种方法将不起作用 - 因为app.run()不返回,所以您只能在线程中调用一个此类函数。

但如果你仔细观察,就会发现quart两者的情况都并非如此。虽然 Quart 示例确实用于app.run()为应用程序提供服务,但如果您看一下 的实现app.run(),您会发现它调用了便利函数run_app(),该函数简单地创建了一个服务器并永远旋转主循环:

def run_app(...):
    loop = asyncio.get_event_loop()
    # ...
    create_server = loop.create_server(
        lambda: Server(app, loop, ...), host, port, ...)
    server = loop.run_until_complete(create_server)
    # ...
    loop.run_forever()
Run Code Online (Sandbox Code Playgroud)

如果您需要控制事件循环的实际运行方式,您始终可以自己完成:

# obtain the event loop from asyncio
loop = asyncio.get_event_loop()

# hook Goblin to the loop
goblin_app = loop.run_until_complete(Goblin.open(loop))
goblin_app.register(Person, Knows)

# hook Quart to the loop
quart_server = loop.run_until_complete(loop.create_server(
        lambda: quart.serving.Server(quart_app, loop), host, port))

# actually run the loop (and the program)
try:
    loop.run_forever()
except KeyboardInterrupt:  # pragma: no cover
    pass
finally:
    quart_server.close()
    loop.run_until_complete(quart_server.wait_closed())
    loop.run_until_complete(loop.shutdown_asyncgens())
    loop.close()
Run Code Online (Sandbox Code Playgroud)

  • @SmartManoj 在撰写此答案时,“asyncio.run()”尚不可用。(它于 2018 年 6 月在 Python 3.7.0 中引入。)如果“Quart.run”现在使用“asyncio.run()”,那么从技术上讲,这是一个不兼容的更改,会使响应的第一部分无效。第二部分应该仍然可以正常工作,并且可能应该更新为使用 `asyncio.run()` 本身。 (2认同)