带有 asyncio 的惰性迭代器(生成器)
Lazy iterators (generators) with 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
。
更新:
从 Python 3.6 开始,我们有 asynchronous generators 并且能够在协程中直接使用 yield
。
如上所述,您不能在 async
函数中使用 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]
您可能还想看看 ,其中 StopAsyncIteration
使用。
我有这样一个阻塞的非异步代码:
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
。
更新:
从 Python 3.6 开始,我们有 asynchronous generators 并且能够在协程中直接使用 yield
。
如上所述,您不能在 async
函数中使用 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]
您可能还想看看 StopAsyncIteration
使用。