python aiohttp 到现有的事件循环

python aiohttp into existing event loop

我正在测试 aiohttp 和 asyncio。我希望同一个事件循环有一个套接字、http 服务器、http 客户端。

我正在使用这个示例代码:

@routes.get('/')
async def hello(request):
    return web.Response(text="Hello, world")

app = web.Application()
app.add_routes(routes)
web.run_app(app)

问题是 run_app 正在阻塞。我想将 http 服务器添加到我使用以下方法创建的现有事件循环中:

asyncio.get_event_loop()

The problem is run_app is blocking. I want to add the http server into an existing event loop

run_app只是方便API。要挂接到现有的事件循环,您可以直接实例化 AppRunner:

loop = asyncio.get_event_loop()
# add stuff to the loop
...

# set up aiohttp - like run_app, but non-blocking
runner = aiohttp.web.AppRunner(app)
loop.run_until_complete(runner.setup())
site = aiohttp.web.TCPSite(runner)    
loop.run_until_complete(site.start())

# add more stuff to the loop
...

loop.run_forever()

在 asyncio 3.8 及更高版本中,您可以使用 asyncio.run():

async def main():
    # add stuff to the loop, e.g. using asyncio.create_task()
    ...

    runner = aiohttp.web.AppRunner(app)
    await runner.setup()
    site = aiohttp.web.TCPSite(runner)    
    await site.start()

    # add more stuff to the loop, if needed
    ...

    # wait forever
    await asyncio.Event().wait()

asyncio.run(main())

对于来自 Google 的未来旅行者,这里有一个更简单的方法。

async def main():
    await aio.gather(
        web._run_app(app, port=args.port),
        SomeotherTask(),
        AndAnotherTask()
    )

aio.run(main())

说明: web.runapp 是对内部函数 web._runapp 的精简包装。该函数使用旧式方法获取事件循环,然后调用 loop.run_until_complete.

我们将其替换为 aio.gather 以及我们想要同时 运行 的其他任务,并使用 aio.run 来安排它们

Source