如何从Quart获取事件循环

时间:2018-02-25 02:39:37

标签: python python-asyncio quart goblin

您好我是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)

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

有谁知道我怎么能得到它?任何帮助将受到高度赞赏。

1 个答案:

答案 0 :(得分:4)

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

在基于asyncio的应用程序中,事件循环通常不归Quart或任何其他协议/应用程序级别组件所有,它由asyncio提供,或者可能是uvloop之类的加速器。通过调用asyncio.get_event_loop()获取事件循环,有时使用asyncio.set_event_loop()设置。

这是Quart的app.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()方法来旋转事件循环,那么这种方法就不会起作用 - 因为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()

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

# 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()