带有asyncio的惰性迭代器(生成器)

vad*_*vad 8 python asynchronous python-asyncio

我有一个像这样的阻塞,非异步代码:

def f():
    def inner():
        while True:
            yield read()
    return inner()
Run Code Online (Sandbox Code Playgroud)

使用此代码,调用者可以选择何时停止函数以生成数据.如何将此更改为异步?此解决方案不起作用:

async def f():
    async def inner():
        while True:
            yield await coroutine_read()
    return inner()
Run Code Online (Sandbox Code Playgroud)

...因为 yield不能用于async def功能.如果我asyncinner()签名中删除,我不能再使用await了.

Mik*_*mov 7

如上所述,您不能使用yield内部功能yield.如果你想创建协程生成器,你必须手动,使用async__aiter__魔术方法:

import asyncio


# `coroutine_read()` generates some data:
i = 0
async def coroutine_read():
    global i
    i += 1
    await asyncio.sleep(i)
    return i


# `f()` is asynchronous iterator.
# Since we don't raise `StopAsyncIteration` 
# it works "like" `while True`, until we manually break.
class f:
    async def __aiter__(self):
        return self

    async def __anext__(self):
        return await coroutine_read()


# Use f() as asynchronous iterator with `async for`:
async def main():
    async for i in f():
        print(i)
        if i >= 3:
            break


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
Run Code Online (Sandbox Code Playgroud)

输出:

1
2
3
[Finished in 6.2s]
Run Code Online (Sandbox Code Playgroud)

您可能还希望看到其他帖子,在哪里__anext__使用.

UPD:

从Python 3.6开始,我们有异步生成器,可以StopAsyncIteration直接在协同程序中使用.