【问题标题】:How to use an async for loop to iterate over a list?如何使用异步 for 循环遍历列表?
【发布时间】:2023-03-26 22:17:01
【问题描述】:

所以我需要为列表中的所有项目调用async 函数。这可能是一个 URL 列表和一个使用 aiohttp 的异步函数,该函数从每个 URL 获取响应。现在显然我不能执行以下操作:

async for url in ['www.google.com', 'www.youtube.com', 'www.aol.com']:

我可以使用普通的 for 循环,但是我的代码会同步运行,我失去了拥有 async 响应获取功能的好处和速度。

有什么方法可以转换列表以使上述工作正常吗?我只需要将列表的__iter__() 更改为__aiter__() 方法,对吗?这可以通过子类化列表来实现吗?也许将它封装在一个类中?

【问题讨论】:

    标签: python python-3.x asynchronous iterator python-asyncio


    【解决方案1】:

    使用asyncio.as_completed:

    for future in asyncio.as_completed(map(fetch, urls)):
        result = await future
    

    asyncio.gather:

    results = await asyncio.gather(map(fetch, urls))
    

    编辑:如果你不介意有外部依赖,你可以使用aiostream.stream.map

    from aiostream import stream, pipe
    
    async def fetch_many(urls):
        xs = stream.iterate(urls) | pipe.map(fetch, ordered=True, task_limit=10)
        async for result in xs:
            print(result)
    

    您可以使用task_limit 参数控制同时运行的fetch 协程的数量,并选择是按顺序获得结果,还是尽快获得结果。

    demonstrationdocumentation 中查看更多示例。

    免责声明:我是项目维护者。

    【讨论】:

    • 但是在这里您使用的是 map,这本质上就像一个普通的 for 循环,将函数应用于列表中的每个元素。为什么这会更快,它是如何异步的? Map 还受到 fetch 函数可以接收的参数数量的限制。我也计划通过 aiohttp 会话。
    • @MaxSmith 在这种情况下,map 只是创建协程。然后as_completed(或gather,或wait)安排它们,以便它们可以同时运行。不需要async for 循环,因为异步调用是在循环内完成的(而不是在iter/next 调用中)
    • 谢谢,这似乎工作得很好,只是现在程序崩溃了,因为打开的套接字太多......我想我需要信号量......
    • @MaxSmith 查看我的编辑以解决您的套接字问题。
    【解决方案2】:

    请注意,文森特的回答存在部分问题:
    您必须在map 函数前面有一个splatter operator,否则asyncio.gather 会尝试使用整个列表。所以这样做:

    results = await asyncio.gather(*map(fetch, url))
    

    【讨论】:

      猜你喜欢
      • 2019-09-07
      • 1970-01-01
      • 1970-01-01
      • 2016-04-14
      • 1970-01-01
      • 1970-01-01
      • 2022-01-06
      • 2022-11-22
      • 1970-01-01
      相关资源
      最近更新 更多