如何在asyncio循环中等待?

e-s*_*tis 14 python python-3.x async-await python-asyncio

这是一个玩具示例,使用asyncio和aiohttp从多个网站下载主页:

import asyncio
import aiohttp

sites = [
    "http://google.com",
    "http://reddit.com",
    "http://wikipedia.com",
    "http://afpy.org",
    "http://httpbin.org",
    "http://stackoverflow.com",
    "http://reddit.com"
]


async def main(sites):
    for site in sites:
        download(site)


async def download(site):
    response = await client.get(site)
    content = await response.read()
    print(site, len(content))


loop = asyncio.get_event_loop()
client = aiohttp.ClientSession(loop=loop)
content = loop.run_until_complete(main(sites))
client.close()
Run Code Online (Sandbox Code Playgroud)

如果我运行它,我得到:

RuntimeWarning: coroutine 'download' was never awaited
Run Code Online (Sandbox Code Playgroud)

但我不想等待它.

在扭曲我可以做:

for site in sites:
    download(site)
Run Code Online (Sandbox Code Playgroud)

如果我没有明确地"收益"或向返回的Deferred添加回调,它只会在没有阻塞或抱怨的情况下运行.我无法访问结果,但在这种情况下我不需要它.

在JS我可以这样做:

site.forEarch(site){
    donwload(site)
}
Run Code Online (Sandbox Code Playgroud)

而且,它不会阻止,也不需要我的任何部分.

我找到了办法:

async def main(sites):
    await asyncio.wait([download(site) for site in sites])
Run Code Online (Sandbox Code Playgroud)

但:

  • 找到它真的不明显.我很难记住.
  • 很难理解它的作用."等待"似乎说"我阻止",但没有清楚地传达它阻止整个协程列表完成.
  • 你不能传入一个生成器,它需要是一个真正的列表,我觉得在Python中真的不自然.
  • 如果我只有一个等待的怎么办?
  • 如果我不想在我的任务上等待,并安排它们执行然后继续我的其余代码怎么办?
  • 这种方式更加冗长扭曲和JS解决方案.

有更好的方法吗?

Vin*_*ent 9

要将协程安排为任务,请使用asyncio.ensure_future:

for site in sites:
    coro = download(site)
    future = asyncio.ensure_future(coro)
Run Code Online (Sandbox Code Playgroud)

它取代了版本3.4.4中已弃用的函数asyncio.async.

然后你就可以管理使用这些期货await,asyncio.waitasyncio.gather.

  • 如今,建议改为[create_task}(https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task)。 (3认同)

Jas*_*ohi -11

  • 这实在是不太明显的找出来。我很难记住。

有关协程的文档确实非常清楚地说明了asyncio.wait协程的用途。

  • 很难理解它的作用。“waits”似乎在说“i block”,但没有清楚地传达它阻止整个协程列表完成。

再次,请参阅文档。

  • 你不能传入一个生成器,它需要是一个真实的列表,我觉得这在Python中非常不自然。

再次,具体看文档asyncio.as_completed

  • 如果我只有一个等待怎么办?

它应该仍然有效。

  • 如果我根本不想等待我的任务,而只想安排它们执行,然后继续执行其余代码怎么办?

然后你就可以使用asyncio.ensure_furture. 事实上,asyncio.wait它是一个方便的函数asyncio.ensure_future(以及一些其他逻辑)。

  • 它比扭曲和 JS 解决方案更冗长。

也许吧,但这并不是一件坏事(从我的角度来看)。

  • 接受并投了赞成票,它确实解决了我的问题。然而:文档并不是那么明显(甚至 Guido 也知道这一点)。对于如此简单的问题必须去看医生并不是良好人体工程学的标志。更重要的是,比 Twisted 和 JS 更冗长的 2 个非常冗长的技术绝对不是荣誉徽章。特别是现在您只能运行一个事件循环,因此不自动使用默认事件循环似乎有点过分了。但谢谢,现在更明显了。 (2认同)