如何构建异步发电机?

How to build an asynchronous generator?

提问人:tobias 提问时间:11/10/2023 更新时间:11/11/2023 访问量:73

问:

当我运行代码时

async def main(*args, **kwargs):
    await sub_process1()

async def sub_process1():
    iter = await sub_process2()
    for i in iter:
        yield i

async def sub_process2():
    return [1, 2, 3]

我得到

    async def main(*args, **kwargs):
>       await sub_process1()
E       TypeError: object async_generator can't be used in 'await' expression

如果我使用

async def sub_process1():
    iter = await sub_process2()
    async for i in iter:
        yield i

相反。

我该如何解决这个问题?

python-3.x 异步 async-await 生成器

评论

1赞 user2357112 11/10/2023
你有一个异步生成器。(它并没有真正异步地做一些事情,但从技术上讲,它是一个异步生成器。你为什么要这样做?await
0赞 tobias 11/10/2023
我的想法是尽可能多地保持异步,如果函数变得同步,那么这将对其他位置产生不利影响。

答:

1赞 Ahmed AEK 11/10/2023 #1

生成器(异步与否)在创建时不做任何工作,当你遍历它(for 循环/异步 for 循环)时,它开始做工作,或者当你调用或调用它时,它开始做等效的工作。nextanext

异步生成器和普通生成器之间的区别在于,异步生成器可以用来挂起自身,这反过来又会挂起异步迭代它的人,虽然不会停止事件循环,但事件循环仍然可以在等待时处理其他异步任务。await

为了遍历异步生成器,您需要使用async for

以下示例说明了差异

import asyncio
import time

async def main(*args, **kwargs):
    async for i in sub_process1(): # async generator async for
        print(i) 

async def sub_process1():
    async for i in sub_process2():  # async generator async for
        yield i
    
    # what happens under the hood
    generator = sub_process2() 
    try:
        while True:
           i = await anext(generator)
           yield i
    except StopAsyncIteration:
        pass
    
async def sub_process2(): # async generator
    for i in range(10):  # non async generator normal for
        yield i
        await asyncio.sleep(1) ## suspends sub_process1 and main but not the eventloop
        # this could be any awaitable IO, not a sleep
    for i in range(10):
        yield i
        time.sleep(1) ## suspends the eventloop
        # this could be any blocking IO, not a sleep

def sub_process3(): # non async generator
    for i in range(10):
        yield i
        # await asyncio.sleep(1) ## won't compile 

asyncio.run(main())