对Python异步生成器的误解

0 投票
1 回答
33 浏览
提问于 2025-04-14 18:20

我刚接触 asyncio,特别是 Python 中的异步生成器。这里有一段我不太理解行为的基本代码。它是关于模拟一个等待的睡眠,来获取从远程数据库中返回的值:

import asyncio

async def async_gen():
    for i in range(5):
        print(f"entering iteration {i}")
        await asyncio.sleep(3)
        print(f"ending iteration {i}")
        yield i

async def main():
    async for value in async_gen():
        print(value)

asyncio.run(main())

我期望的是:

  • 在每次循环中,i 会打印 entering iteration i
  • 然后等待 3 秒后,立刻进入下一次循环 i+1,并打印 entering iteration i+1

换句话说,我希望所有的 entering 打印都是立刻显示的,而在 3 秒后,所有的 ending 打印也是立刻显示的。总的时间应该是 3 秒:

entering iteration 0
entering iteration 1
entering iteration 2
entering iteration 3
entering iteration 4
ending iteration 0
0
ending iteration 1
1
ending iteration 2
2
ending iteration 3
3
ending iteration 4
4

但是,执行的结果是每次 entering iteration iending iteration i 之间都有 3 秒的间隔,总时间变成了 5*3秒 = 15秒:

entering iteration 0
ending iteration 0
0
entering iteration 1
ending iteration 1
1
entering iteration 2
ending iteration 2
2
entering iteration 3
ending iteration 3
3
entering iteration 4
ending iteration 4
4

我确定我有些地方没有理解透彻。

任何帮助都非常欢迎。

非常感谢

祝好

1 个回答

0

在你的情况中,main() 是唯一的任务。如果你想要并发处理,就需要为每次循环创建一个单独的任务。

比如说:

import asyncio


async def some_func(i: int):
    print(f"entering iteration {i}")
    await asyncio.sleep(3)
    print(f"ending iteration {i}")


async def async_gen():
    for i in range(5):
        yield i


async def main():
    tasks = []

    async for value in async_gen():
        # launching concurrent task
        task = asyncio.create_task(some_func(value))
        tasks.append(task)

    # wait for all tasks to finish
    await asyncio.gather(*tasks)


asyncio.run(main())

撰写回答