2016-05-17 68 views
5

我有堵塞,不異步代碼:懶惰迭代器(發電機)與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://stackoverflow.com/a/37572657/1113207 –

回答

5

如上所述,您不能在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內部協同程序。