我得出的假设是,如果我用asyncio编写相互递归的协同程序,它们就不会达到最大递归深度异常,因为事件循环正在调用它们(并且像蹦床一样) . 但是,当我这样写它时,情况并非如此:
import asyncio
@asyncio.coroutine
def a(n):
print("A: {}".format(n))
if n > 1000: return n
else: yield from b(n+1)
@asyncio.coroutine
def b(n):
print("B: {}".format(n))
yield from a(n+1)
loop = asyncio.get_event_loop()
loop.run_until_complete(a(0))
当这个运行时,我得到 RuntimeError: maximum recursion depth exceeded while calling a Python object
.
有没有办法防止堆栈在使用asyncio的递归协同程序中增长?
2 回答
为了防止堆栈增长,您必须允许每个协程在调度下一个递归调用后实际退出,这意味着您必须避免使用
yield from
. 相反,您使用asyncio.async(或asyncio.ensure_future
,如果使用Python 3.4.4)使用事件循环调度下一个协同程序,并使用Future.add_done_callback来安排在递归调用返回后运行的回调 . 然后每个协同程序返回一个asyncio.Future
对象,该对象的结果集在其调度的递归调用完成时运行的回调中 .如果您真正看到代码,可能最容易理解:
现在,您的示例代码实际上并没有返回
n
一直支持堆栈,因此您可以创建功能相同的东西,这样做会更简单:但是我怀疑你真的想要一直回归
n
.我将代码更改为
async
,await
和测量时间 . 我真的很喜欢它的可读性 .未来:
结果:
异步,等待:
结果: