【问题标题】:How to not await in a loop with asyncio?如何不使用 asyncio 在循环中等待?
【发布时间】:2016-03-24 04:23:30
【问题描述】:

这是一个使用 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()

如果我运行它,我会得到:

RuntimeWarning: coroutine 'download' was never awaited

但我不想等待。

在扭曲中我可以做到:

for site in sites:
    download(site)

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

在 JS 中我可以做到:

site.forEarch(site){
    donwload(site)
}

再说一次,它不会阻塞,也不需要我做任何事情。

我找到了办法:

async def main(sites):
    await asyncio.wait([download(site) for site in sites])

但是:

  • 这真的不是很明显要找出来。我很难记住。
  • 很难理解它的作用。 “waits”似乎是“i block”,但并没有清楚地传达它阻塞整个协程列表完成。
  • 你不能传入一个生成器,它必须是一个真实的列表,我觉得这在 Python 中真的很不自然。
  • 如果我只有一个 awaitable 怎么办?
  • 如果我根本不想等待我的任务,而只是安排它们执行然后继续我的其余代码怎么办?
  • 它比twisted 和JS 解决方案更冗长。

还有更好的方法吗?

【问题讨论】:

    标签: python python-3.x async-await python-asyncio


    【解决方案1】:

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

    for site in sites:
        coro = download(site)
        future = asyncio.ensure_future(coro)
    

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

    然后您可以使用awaitasyncio.waitasyncio.gather 管理这些期货。

    【讨论】:

    【解决方案2】:
    • 这真的不是很明显要找出来。我很难记住。

    coroutines 上的文档确实非常清楚 asyncio.wait 的目的是什么。

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

    再次,请参阅文档。

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

    再次,请参阅文档,特别是 asyncio.as_completed

    • 如果我只有一个可等待的呢?

    它应该仍然有效。

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

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

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

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

    【讨论】:

    • 接受并赞成它确实解决了我的问题。但是:文档并不那么明显(甚至 Guido 也知道这一点)。对于这样一个简单的问题,必须去看医生并不是人体工程学良好的标志。更重要的是,比 Twisted 和 JS 更冗长,2 非常冗长的技术绝对不是荣誉徽章。特别是因为现在你只能运行一个事件循环,所以不自动使用默认的事件循环似乎有点过头了。不过谢谢,现在更明显了。
    • 还不错;这对我来说可能很明显,因为我一直在使用它。我绝对可以理解人们迷失在文档中。有这么多的部分。 asyncio 文档需要像快速指南这样的教程,就像许多其他模块的文档一样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-07
    • 1970-01-01
    • 1970-01-01
    • 2019-05-22
    相关资源
    最近更新 更多