懒惰迭代器(发电机)与ASYNCIO

问题描述:

我有堵塞,不异步代码:懒惰迭代器(发电机)与ASYNCIO

def f(): 
    def inner(): 
     while True: 
      yield read() 
    return inner() 

这段代码的调用者可以选择何时停止生成数据的功能。如何将其更改为异步?此解决方案不起作用:

async def f(): 
    async def inner(): 
     while True: 
      yield await coroutine_read() 
    return inner() 

...因为yield不能async def功能一起使用。如果我从inner()签名中删除async,我不能再使用await

+0

使用asyncio时,您不需要'yield read()',因为'await'将在幕后完成。这当然不回答这个问题。 –

+1

PEP-0492 [不包含](https://www.python.org/dev/peps/pep-0492/#coroutine-generators)coroutine-generators(这是你想要的),所以,由于PEP仅在3.5中实现,我想答案是“没有办法做到这一点”。 –

+1

尝试实现方式来产生异步函数:http://*.com/a/37572657/1113207 –

如上所述,您不能在async funcs内使用yield。如果你想创建coroutine-generator你必须做手工,用__aiter____anext__魔术方法:

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()) 

输出:

1 
2 
3 
[Finished in 6.2s] 

你也可以看到other post,其中StopAsyncIteration用途。

UPD:

与Python 3.6开始,我们有asynchronous generators,并能直接使用yield内部协同程序。