【问题标题】:how to get return value of async coroutine python如何获取异步协程python的返回值
【发布时间】:2021-03-19 15:21:31
【问题描述】:

我是 python 新手,正在尝试学习 asyncio 模块。我对从异步任务中获取返回值感到沮丧。有一个帖子here 谈到了这个话题,但它无法分辨哪个任务返回哪个值(假设某个网页响应比另一个更快)。
下面的代码尝试同时获取三个网页,而不是一个一个地进行。

    import asyncio
    import aiohttp

    async def fetch(url):
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as resp:
                assert resp.status == 200
                return await resp.text()

    def compile_all(urls):
        tasks = []
        for url in urls:
            tasks.append(asyncio.ensure_future(fetch(url)))
        return tasks

    urls = ['https://python.org', 'https://google.com', 'https://amazon.com']
    tasks = compile_all(urls)
    loop = asyncio.get_event_loop()
    a, b, c = loop.run_until_complete(asyncio.gather(*tasks))
    loop.close()

    print(a)
    print(b)
    print(c)

首先,虽然它确实打印了一些 html 文档,但它遇到了 Runtimeerror:RuntimeError: Event loop is closed。

第二,问题是:这真的保证a,b,c会依次对应urls[0],url[1],urls[2]网页的urls列表吗? (我认为异步任务的执行不能保证这一点)。

第三,任何其他更好的方法或在这种情况下我应该使用队列吗?如果是,怎么做?

任何帮助将不胜感激。

【问题讨论】:

  • 使用await 将暂停函数的执行,直到它返回一些东西,但不会阻止其他async 函数运行。如果您是 python 新手,我不建议您使用asyncio 进行多处理,因为它确实很复杂,最适合更有经验的人。
  • 另外,你的问题很奇怪。 “Python 网页”是什么意思?
  • 必须使用工作所需的 asyncio,这就是我需要学习它的原因。我已经修改了我的问题表达,对此感到抱歉。
  • 我明白了。但是“Python 网页”是什么意思?
  • 我无法重现您观察到的RuntimeError。是的,无论它们完成的顺序如何,结果都将对应于 URL 的序列。

标签: python-3.x python-asyncio


【解决方案1】:

结果的顺序将与 url 的顺序相对应。查看asyncio.gather 的文档:

如果所有 awaitables 都成功完成,结果是 返回值的聚合列表。结果值的顺序 对应于 aws 中 awaitable 的顺序。

要在任务完成时处理任务,您可以使用asyncio.as_completed。这个post 有更多关于如何使用它的信息。

【讨论】:

  • 感谢您的回答。这证实了 collect() 仅在所有任务完成后返回结果列表......但是,这违背了我使用 asyncio 同时获取网页(或执行 I/O 任务)的意图。我使用 asyncio 的目的是避免被任何响应缓慢的网站阻止。到最后,就和一个一个去取一样……还有什么更好的办法吗?
  • @Spark 你可以在 aiohttp ClientSession 中设置timeout 来中止慢速网站。
  • 谢谢。设置超时意味着我必须放弃那些速度慢的网站,即使它们可能只是偶尔很慢。我的想法是假设事件循环可以通过先进先出缓冲区或队列等机制从首先完成的任务返回结果,因此多任务的异步执行实际上变成了管道吐痰结果......
  • @Spark 不一样。如果您要获取的网站分别需要 1、2 和 3 秒,那么一个接一个地获取它们需要 6 秒。使用gather() 获取它们只需 3 秒,因此显然更好。如果你想对第一秒做出反应,可以使用asyncio.as_completed
  • @user4815162342。非常感谢,它看起来 as_completed 完全符合我使用 asyncio 的意图,尽管它返回生成器。我得到了三个 google 的 html 文档首先出现(如预期的那样)....关于 RuntimeError,我有一段时间无法重现它,但我发现 this 解释了。顺便说一句,我正在使用 python 3.8
猜你喜欢
  • 1970-01-01
  • 2013-09-07
  • 1970-01-01
  • 2020-04-20
  • 1970-01-01
  • 1970-01-01
  • 2018-02-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多